Showing preview only (436K chars total). Download the full file or copy to clipboard to get everything.
Repository: AvicennaJr/Nuru
Branch: main
Commit: 78076bbdc2b5
Files: 166
Total size: 399.8 KB
Directory structure:
gitextract_yf7p31zd/
├── .github/
│ ├── ISSUE_TEMPLATE/
│ │ ├── bug-report.yml
│ │ └── feature-request.yml
│ ├── PULL_REQUEST_TEMPLATE
│ └── workflows/
│ ├── build.yml
│ └── tests.yml
├── .gitignore
├── .goreleaser.yaml
├── ABOUT.md
├── LICENSE
├── Makefile
├── README.md
├── ast/
│ ├── ast.go
│ └── ast_test.go
├── evaluator/
│ ├── assign.go
│ ├── assignEqual.go
│ ├── at.go
│ ├── bang.go
│ ├── block.go
│ ├── builtins.go
│ ├── builtins_common.go
│ ├── builtins_wasm.go
│ ├── call.go
│ ├── dict.go
│ ├── error_handler.go
│ ├── evaluator.go
│ ├── evaluator_test.go
│ ├── forin.go
│ ├── function.go
│ ├── identifier.go
│ ├── if.go
│ ├── import.go
│ ├── in.go
│ ├── index.go
│ ├── infix.go
│ ├── method.go
│ ├── package.go
│ ├── postfix.go
│ ├── prefix.go
│ ├── property.go
│ ├── switch.go
│ ├── type.go
│ └── while.go
├── examples/
│ ├── Astart.nr
│ ├── example.nr
│ ├── perceptron.nr
│ ├── reduce.nr
│ ├── sarufi.nr
│ ├── sorting_algorithm.nr
│ └── sudoku_solver.nr
├── extensions/
│ ├── README.md
│ ├── vim/
│ │ └── syntax/
│ │ └── nuru.vim
│ └── vscode/
│ ├── CHANGELOG.md
│ └── README.md
├── go.mod
├── go.sum
├── gotest
├── lexer/
│ ├── lexer.go
│ └── lexer_test.go
├── main.go
├── main_wasm.go
├── module/
│ ├── hisabati.go
│ ├── json.go
│ ├── module.go
│ ├── net.go
│ ├── os.go
│ └── time.go
├── object/
│ ├── array.go
│ ├── at.go
│ ├── bool.go
│ ├── break.go
│ ├── builtin.go
│ ├── byte.go
│ ├── continue.go
│ ├── dict.go
│ ├── environment.go
│ ├── error.go
│ ├── error_wasm.go
│ ├── file.go
│ ├── float.go
│ ├── function.go
│ ├── instance.go
│ ├── integer.go
│ ├── module.go
│ ├── null.go
│ ├── object.go
│ ├── object_test.go
│ ├── package.go
│ ├── return.go
│ ├── strings.go
│ └── time.go
├── parser/
│ ├── arrays.go
│ ├── assignEqual.go
│ ├── assignment.go
│ ├── at.go
│ ├── boolean.go
│ ├── break.go
│ ├── continue.go
│ ├── dict.go
│ ├── dot.go
│ ├── float.go
│ ├── for.go
│ ├── function.go
│ ├── identifier.go
│ ├── if.go
│ ├── import.go
│ ├── index.go
│ ├── integer.go
│ ├── null.go
│ ├── package.go
│ ├── parser.go
│ ├── parser_test.go
│ ├── statements.go
│ ├── string.go
│ ├── switch.go
│ └── while.go
├── repl/
│ ├── docs/
│ │ ├── en/
│ │ │ ├── README.md
│ │ │ ├── arrays.md
│ │ │ ├── bool.md
│ │ │ ├── builtins.md
│ │ │ ├── comments.md
│ │ │ ├── dictionaries.md
│ │ │ ├── files.md
│ │ │ ├── for.md
│ │ │ ├── function.md
│ │ │ ├── hisabati.md
│ │ │ ├── identifiers.md
│ │ │ ├── ifStatements.md
│ │ │ ├── json.md
│ │ │ ├── keywords.md
│ │ │ ├── net.md
│ │ │ ├── null.md
│ │ │ ├── numbers.md
│ │ │ ├── operators.md
│ │ │ ├── packages.md
│ │ │ ├── range.md
│ │ │ ├── strings.md
│ │ │ ├── switch.md
│ │ │ ├── time.md
│ │ │ └── while.md
│ │ └── sw/
│ │ ├── README.md
│ │ ├── arrays.md
│ │ ├── bools.md
│ │ ├── builtins.md
│ │ ├── dictionaries.md
│ │ ├── for.md
│ │ ├── functions.md
│ │ ├── identifiers.md
│ │ ├── if.md
│ │ ├── keywords.md
│ │ ├── maoni.md
│ │ ├── null.md
│ │ ├── numbers.md
│ │ ├── operators.md
│ │ ├── range.md
│ │ ├── strings.md
│ │ ├── switch.md
│ │ └── while.md
│ ├── docs.go
│ └── repl.go
├── sh/
│ └── install.sh
├── styles/
│ └── styles.go
├── third_party/
│ └── math/
│ ├── README.md
│ ├── hesabu.nr
│ └── test.nr
├── token/
│ └── token.go
└── upx
================================================
FILE CONTENTS
================================================
================================================
FILE: .github/ISSUE_TEMPLATE/bug-report.yml
================================================
name: 🐛 Bug Report
description: Report a bug
title: (bug report summary)
labels: Bug
body:
- type: textarea
id: description
attributes:
label: Describe the bug
description: What is the problem? A clear and concise description of the bug.
validations:
required: true
- type: textarea
id: expected
attributes:
label: Expected Behavior
description: What did you expect to happen?
validations:
required: true
- type: textarea
id: current
attributes:
label: Current Behavior
description: |
What actually happened?
Please include full errors, uncaught exceptions, stack traces, and relevant logs.
If service/functions responses are relevant, please include wire logs.
validations:
required: true
- type: textarea
id: reproduction
attributes:
label: Reproduction Steps
description: |
Provide a self-contained, concise snippet of code that can be used to reproduce the issue.
For more complex issues provide a repo with the smallest sample that reproduces the bug.
Avoid including business logic or unrelated code, it makes diagnosis more difficult.
The code sample should be an SSCCE. See http://sscce.org/ for details.
In short, please provide a code sample that we can copy/paste, run and reproduce.
validations:
required: true
- type: textarea
id: solution
attributes:
label: Possible Solution
description: Suggest a fix/reason for the bug
validations:
required: false
- type: textarea
id: context
attributes:
label: Additional Information/Context
description: |
Anything else that might be relevant for troubleshooting this bug.
Providing context helps us come up with a solution that is most useful in the real world.
validations:
required: false
- type: input
id: version
attributes:
label: Nuru version
description: |
Please make sure to use the latest version of Nuru before reporting any issues as it may have already been fixed.
validations:
required: true
- type: textarea
id: environment
attributes:
label: Environment details (OS name and version, etc.)
description: Your operating system (Windows, Linux, Android or MacOS)
validations:
required: true
================================================
FILE: .github/ISSUE_TEMPLATE/feature-request.yml
================================================
name: 🚀 Feature Request
description: Suggest an idea for this project
title: (feature request summary)
labels: Feature Request
body:
- type: textarea
id: description
attributes:
label: Describe the feature
description: A clear and concise description of the feature you are proposing.
validations:
required: true
- type: textarea
id: use-case
attributes:
label: Use Case
description: |
Why do you need this feature? For example: "I'm always frustrated when..."
validations:
required: true
- type: textarea
id: solution
attributes:
label: Proposed Solution
description: Suggest how to implement the addition or change. Please include prototype/workaround/sketch/reference implementation.
validations:
required: false
- type: textarea
id: other
attributes:
label: Other Information
description: Any alternative solutions or features you considered, a more detailed explanation, stack traces, related issues, links for context, etc.
validations:
required: false
- type: checkboxes
id: ack
attributes:
label: Acknowledgements
options:
- label: I may be able to implement this feature request
required: false
- label: This feature might incur a breaking change
required: false
- type: input
id: version
attributes:
label: Version used
description: Please provide the version of the repository or tool you are using.
validations:
required: true
- type: textarea
id: environment
attributes:
label: Environment details (OS name and version, etc.)
description: Your operating system (Linux, Windows, Android or Mac)
validations:
required: true
================================================
FILE: .github/PULL_REQUEST_TEMPLATE
================================================
<!--
Please title your PR as follows: `module: description` (e.g. `time: fix date format`).
Always start with the thing you are fixing, then describe the fix.
Don't use past tense (e.g. "fixed foo bar").
Explain what your PR does and why.
If you are adding a new function, please document it and add tests:
```
// foo does foo and bar
foo = unda() {
// does foo and bar
}
```
If you are fixing a bug, please add a detailed explanation about it.
Before submitting a PR, please run `make test` .
I try to process PRs as soon as possible. They should be handled within 24 hours.
Applying labels to PRs is not needed.
Thanks a lot for your contribution!
-->
================================================
FILE: .github/workflows/build.yml
================================================
name: Go
on:
push:
tags:
- "*"
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Set up Go
uses: actions/setup-go@v3
with:
go-version: 1.21
id: go
- name: Test
run: go mod tidy && make test
- name: Run GoReleaser
uses: goreleaser/goreleaser-action@v5
with:
distribution: goreleaser
version: latest
args: release --clean
env:
GITHUB_TOKEN: ${{ secrets.GO_RELEASER_GITHUB_TOKEN }}
================================================
FILE: .github/workflows/tests.yml
================================================
name: Go
on:
push:
branches: [ main, dev ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Go
uses: actions/setup-go@v3
with:
go-version: 1.21
- name: Test
run: go mod tidy && make test
================================================
FILE: .gitignore
================================================
.DS_Store
*.[56789ao]
*.a[56789o]
*.so
*.pyc
._*
.nfs.*
[56789a].out
*~
*.orig
*.rej
*.exe
.*.swp
core
*.cgo*.go
*.cgo*.c
_cgo_*
_obj
_test
_testmain.go
/VERSION.cache
/bin/
/build.out
/doc/articles/wiki/*.bin
/goinstall.log
/last-change
/misc/cgo/life/run.out
/misc/cgo/stdio/run.out
/misc/cgo/testso/main
/pkg/
/src/*.*/
/src/cmd/cgo/zdefaultcc.go
/src/cmd/dist/dist
/src/cmd/go/internal/cfg/zdefaultcc.go
/src/cmd/go/internal/cfg/zosarch.go
/src/cmd/internal/objabi/zbootstrap.go
/src/go/build/zcgo.go
/src/go/doc/headscan
/src/runtime/internal/sys/zversion.go
/src/unicode/maketables
/test.out
/test/garbage/*.out
/test/pass.out
/test/run.out
/test/times.out
#Personal
testbinaries/
tests_random/
nuru
Notes.md
tutorials/en/*
config.json
*local*
# For Nuru executables
/nuru
/Nuru
dist/
*.wasm
================================================
FILE: .goreleaser.yaml
================================================
project_name: nuru
before:
hooks:
- go mod tidy
- go generate ./...
builds:
- env:
- CGO_ENABLED=0
goos:
- linux
- windows
- darwin
- android
ldflags:
- "-s -w"
ignore:
- goos: android
goarch: 386
archives:
- format: tar.gz
name_template: >-
nuru_
{{- title .Os }}_
{{- if eq .Arch "amd64" }}amd64
{{- else if eq .Arch "386" }}i386
{{- else }}{{ .Arch }}{{ end }}
{{- if .Arm }}v{{ .Arm }}{{ end }}
format_overrides:
- goos: windows
format: zip
changelog:
sort: asc
filters:
exclude:
- "^docs:"
- "^test:"
nfpms:
- maintainer: "AvicennaJr"
homepage: "https://nuruprogramming.org"
description: "Nuru is a programming language built from the ground up"
formats:
- deb
file_name_template: "{{ .ProjectName }}.{{ .Os }}-{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}"
================================================
FILE: ABOUT.md
================================================
# NURU PROGRAMMING LANGUAGE
This 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.
## Background
This 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.
With 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.
Now 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:
- 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.
- 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.
## Purpose
Nuru 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.
Nuru 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.
While 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.
## Philosophy
Nuru'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.
Nuru is also community driven. We listen to our community and do our best to implement on the feedback we get from them.
## Where Not To Use Nuru
Nuru'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.
## Challenges
The 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.
## Future Of Nuru
It 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.
We also hope to see games and GUI applications written in Nuru in the near future... God willing.
## Final Words
I 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.
And finally, I thank Allah for granting us the ability to learn and giving me the ability to make such a project.
================================================
FILE: LICENSE
================================================
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.
================================================
FILE: Makefile
================================================
VERSION=0.5.1
build_linux:
@echo 'building linux binary...'
env GOOS=linux GOARCH=amd64 go build -ldflags="-s -w" -o nuru
@echo 'shrinking binary...'
./upx --brute nuru
@echo 'zipping build....'
tar -zcvf nuru_linux_amd64_v${VERSION}.tar.gz nuru
@echo 'cleaning up...'
rm nuru
build_windows:
@echo 'building windows executable...'
env GOOS=windows GOARCH=amd64 go build -ldflags="-s -w" -o nuru_windows_amd64_v${VERSION}.exe
@echo 'shrinking build...'
./upx --brute nuru_windows_amd64_v${VERSION}.exe
build_mac:
@echo 'building mac binary...'
env GOOS=darwin GOARCH=amd64 go build -ldflags="-s -w" -o nuru
@echo 'shrinking binary...'
./upx --brute nuru
@echo 'zipping build...'
tar -zcvf nuru_mac_amd64_v${VERSION}.tar.gz nuru
@echo 'cleaning up...'
rm nuru
build_android:
@echo 'building android binary'
env GOOS=android GOARCH=arm64 go build -ldflags="-s -w" -o nuru
@echo 'zipping build...'
tar -zcvf nuru_android_arm64_v${VERSION}.tar.gz nuru
@echo 'cleaning up...'
rm nuru
build_wasm:
@echo 'building wasm binary'
GOOS=js GOARCH=wasm go build -o nuru.wasm
@echo 'zipping build...'
tar -zcvf nuru_wasm_v${VERSION}.tar.gz nuru.wasm
@echo 'cleaning up...'
rm nuru.wasm
build_test:
go build -ldflags="-s -w" -o nuru
dependencies:
@echo 'checking dependencies...'
go mod tidy
test:
@echo -e '\nTesting Lexer...'
@./gotest --format testname ./lexer/
@echo -e '\nTesting Parser...'
@./gotest --format testname ./parser/
@echo -e '\nTesting AST...'
@./gotest --format testname ./ast/
@echo -e '\nTesting Object...'
@./gotest --format testname ./object/
@echo -e '\nTesting Evaluator...'
@./gotest --format testname ./evaluator/
clean:
go clean
================================================
FILE: README.md
================================================
<h1 align="center">NURU🔥PROGRAMMING🔥LANGUAGE</h1>
<p align="center">
<a href="https://github.com/NuruProgramming/Nuru"><img alt="Nuru Programming Language" src="https://img.shields.io/badge/Nuru-Programming%20Language-yellow"></a>
<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>
<a href="https://github.com/NuruProgramming/Nuru"><img alt="Nuru Programming Language" src="https://img.shields.io/github/last-commit/AvicennaJr/Nuru"></a>
<br>
<a href="https://github.com/NuruProgramming/Nuru"><img alt="Nuru Programming Language" src="https://img.shields.io/github/downloads/avicennajr/nuru/total"></a>
<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>
<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>
<br>
<a href="https://github.com/NuruProgramming/Nuru"><img alt="Nuru Programming Language" src="https://img.shields.io/github/stars/AvicennaJr/Nuru?style=social"></a>
</p>
A Swahili Programming Language of its kind built from the ground up.
## Installation
To get started download the executables from the release page or follow the instructions for your device below:
### Linux
- Download the binary:
```
curl -O -L https://github.com/NuruProgramming/Nuru/releases/download/v0.5.18/nuru_Linux_amd64.tar.gz
```
- Extract the file to make global available:
```
sudo tar -C /usr/local/bin -xzvf nuru_Linux_amd64.tar.gz
```
- Confirm installation with:
```
nuru -v
```
### MacOs ( Apple silicon Mac )
- Download the binary:
- For apple silicon mac use:
```
curl -O -L https://github.com/NuruProgramming/Nuru/releases/download/v0.5.18/nuru_Darwin_arm64.tar.gz
```
- For apple intel mac use:
```
curl -O -L https://github.com/NuruProgramming/Nuru/releases/download/v0.5.18/nuru_Darwin_amd64.tar.gz
```
- Extract the file to make global available:
- For apple silicon mac use:
```
sudo tar -C /usr/local/bin -xzvf nuru_Darwin_arm64.tar.gz
```
- For apple intel mac use:
```
sudo tar -C /usr/local/bin -xzvf nuru_Darwin_amd64.tar.gz
```
- Confirm installation with:
```
nuru -v
```
### Android (Termux)
To install Nuru on your Android device using Termux, follow these steps:
1. **Ensure Termux is installed**:
- You can download and install [Termux](https://f-droid.org/en/packages/com.termux/).
2. **Create the target directory**:
```bash
mkdir -p /data/data/com.termux/files/usr/share/nuru
```
3. **Download the Nuru package**:
```bash
curl -O -L https://github.com/NuruProgramming/Nuru/releases/download/v0.5.18/nuru_Android_arm64.tar.gz
```
4. **Extract the files to the target directory**:
```bash
tar -xzvf nuru_Android_arm64.tar.gz -C /data/data/com.termux/files/usr/share/nuru
```
5. **Set up an alias for easy access**:
```bash
echo "alias nuru='/data/data/com.termux/files/usr/share/nuru/nuru'" >> ~/.bashrc
```
6. **Reload the .bashrc file to apply the alias**:
```bash
source ~/.bashrc
```
7. **Verify the installation**:
```bash
nuru -v
```
For a more streamlined installation, you can use the following one-liner:
```bash
curl -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.."
```
### Windows
- Executable:
- Download the Nuru zip file [Here](https://github.com/NuruProgramming/Nuru/releases/download/v0.5.18/nuru_Windows_amd64.zip)
- Unzip to get the executable
- Double click the executable
- Nuru Installer
> Coming Soon
### Building From Source
- Make sure you have golang installed (atleast 1.19.0 and above)
- Run the following command:
```
go build -o nuru .
```
- Copy nuru binary to path destination ~/go/bin
```
cp nuru ~/go/bin
```
- Confirm installtion with:
```
nuru -v
```
## Syntax At A Glance
**NOTE**
> There is a more detailed documentation of the language [here](https://nuruprogramming.org).
Nuru, although still in its early stage, intends to be a fully functional programming language, and thus it has been baked with many features.
### Defining A Variable
You can define variables like this:
```
x = 2;
y = 3;
andika(x*y) // output is 6
```
You can also use the `fanya` keyword to define a variabe:
```
fanya x = 3
```
**Note that `fanya` keyword is OPTIONAL**
### Comments
Nuru supports both single line and multiple line comments as shown below:
```
// Single line comment
/*
Multiple
Line
Comment
*/
```
### Arithmetic Operations
For now Nuru supports `+`, `-`, `/`, `*` and `%`. Nuru also provides precedence of operations using the BODMAS rule:
```
2 + 2 * 3 // output = 8
2 * (2 + 3) // output = 10
```
### Types
Nuru has the following types:
| Type | Syntax | Comments |
| ------ | ---------------------------------- | ------------------------------------------------------- |
| BOOL | `kweli sikweli` | kweli == true, sikweli == false |
| INT | `1, 100, 342, -4` | These are signed 64 bit integers |
| FLOAT | `2.3, 4.5. 100.8094` | Signed 64 bit floats |
| STRING | `"" "mambo" "habari yako"` | They can be in double `"` or single `'` quotes |
| ARRAY | `[] [1, 2, 3] [1, "moja", kweli]` | Arrays can hold any types |
| DICT | `{} {"a": 3, 1: "moja", kweli: 2}` | Keys can be int, string or bool. Values can be anything |
| NULL | `tupu` | These are nil objects |
### Functions
This is how you define a function in Nuru:
```
jumlisha = unda(x, y) {
rudisha x + y
}
andika(jumlisha(3,4))
```
Nuru also supports recursion:
```
fibo = unda(x) {
kama (x == 0) {
rudisha 0;
} au kama (x == 1) {
rudisha 1;
} sivyo {
rudisha fibo(x - 1) + fibo(x - 2);
}
}
```
### If Statements
Nuru supports if, elif and else statements with keywords `kama`, `au kama` and `sivyo` respectively:
```
kama (2<1) {
andika("Mbili ni ndogo kuliko moja")
} au kama (3 < 1) {
andika ("Tatu ni ndogo kuliko moja")
} sivyo {
andika("Moja ni ndogo")
}
```
### While Loops
Nuru's while loop syntax is as follows:
```
i = 10
wakati (i > 0) {
andika(i)
i--
}
```
### Arrays
This is how you initiliaze and perform other array operations in Nuru:
```
arr = []
// To add elements
sukuma(arr, 2)
andika(arr) // output = [2]
// Add two Arrays
arr2 = [1,2,3,4]
arr3 = arr1 + arr2
andika(arr3) // output = [2,1,2,3,4]
// reassign value
arr3[0] = 0
andika[arr3] // output = [0,1,2,3,4]
// get specific item
andika(arr[3]) // output = 3
```
### Dictionaries
Nuru also supports dictionaries and you can do a lot with them as follows:
```
mtu = {"jina": "Mojo", "kabila": "Mnyakusa"}
// get value from key
andika(mtu["jina"]) // output = Mojo
andika(mtu["kabila"]); // output = Mnyakusa
// You can reassign values
mtu["jina"] = "Avicenna"
andika(mtu["jina"]) // output = Avicenna
// You can also add new values like this:
mtu["anapoishi"] = "Dar Es Salaam"
andika(mtu) // output = {"jina": "Avicenna", "kabila": "Mnyakusa", "anapoishi": "Dar Es Salaam"}
// You can also add two Dictionaries
kazi = {"kazi": "jambazi"}
mtu = mtu + kazi
andika(mtu) // output = {"jina": "Avicenna", "kabila": "Mnyakusa", "anapoishi": "Dar Es Salaam", "kazi": "jambazi"}
```
### For Loops
These can iterate over strings, arrays and dictionaries:
```
kwa i ktk "habari" {
andika(i)
}
/* //output
h
a
b
a
r
i
*/
```
### Getting Input From User
In Nuru you can get input from users using the `jaza()` keyword as follows:
```
jina = jaza("Unaitwa nani? ") // will prompt for input
andika("Habari yako " + jina)
```
## How To Run
### Using The Intepreter:
You can enter the intepreter by simply running the `nuru` command:
```
nuru
>>> andika("karibu")
karibu
>>> 2 + 2
4
```
Kindly Note that everything should be placed in a single line. Here's an example:
```
>>> kama (x > y) {andika("X ni kubwa")} sivyo {andika("Y ni kubwa")}
```
### Running From File
To run a Nuru script, write the `nuru` command followed by the name of the file with a `.nr` or `.sw` extension:
```
nuru myFile.nr
```
## Issues
Kindly open an [Issue](https://github.com/NuruProgramming/Nuru/issues) to make suggestions and anything else.
## Contributions
### Documentation
There 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.
### Code
Clone the repo, hack it, make sure all tests are passing then submit a pull request.
> Make sure ALL tests are passing before making a pull request. You can confirm with running `make test`
## Community
Nuru has a passionate community, join us on [Telegram](https://t.me/NuruProgrammingChat)
## License
[MIT](http://opensource.org/licenses/MIT)
## Authors
Nuru Programming Language has been authored and being actively maintained by [Avicenna](https://github.com/AvicennaJr)
================================================
FILE: ast/ast.go
================================================
package ast
import (
"bytes"
"strings"
"github.com/NuruProgramming/Nuru/token"
)
type Node interface {
TokenLiteral() string
String() string
}
type Statement interface {
Node
statementNode()
}
type Expression interface {
Node
expressionNode()
}
type Program struct {
Statements []Statement
}
func (p *Program) TokenLiteral() string {
if len(p.Statements) > 0 {
return p.Statements[0].TokenLiteral()
} else {
return ""
}
}
func (p *Program) String() string {
var out bytes.Buffer
for _, s := range p.Statements {
out.WriteString(s.String())
}
return out.String()
}
type LetStatement struct {
Token token.Token
Name *Identifier
Value Expression
}
func (ls *LetStatement) statementNode() {}
func (ls *LetStatement) TokenLiteral() string { return ls.Token.Literal }
func (ls *LetStatement) String() string {
var out bytes.Buffer
out.WriteString(ls.TokenLiteral() + " ")
out.WriteString(ls.Name.String())
out.WriteString(" = ")
if ls.Value != nil {
out.WriteString(ls.Value.String())
}
out.WriteString(";")
return out.String()
}
type Identifier struct {
Token token.Token
Value string
}
func (i *Identifier) expressionNode() {}
func (i *Identifier) TokenLiteral() string { return i.Token.Literal }
func (i *Identifier) String() string { return i.Value }
type ReturnStatement struct {
Token token.Token
ReturnValue Expression
}
func (rs *ReturnStatement) statementNode() {}
func (rs *ReturnStatement) TokenLiteral() string { return rs.Token.Literal }
func (rs *ReturnStatement) String() string {
var out bytes.Buffer
out.WriteString(rs.TokenLiteral() + " ")
if rs.ReturnValue != nil {
out.WriteString(rs.ReturnValue.String())
}
out.WriteString(";")
return out.String()
}
type ExpressionStatement struct {
Token token.Token
Expression Expression
}
func (es *ExpressionStatement) statementNode() {}
func (es *ExpressionStatement) TokenLiteral() string { return es.Token.Literal }
func (es *ExpressionStatement) String() string {
if es.Expression != nil {
return es.Expression.String()
}
return ""
}
type IntegerLiteral struct {
Token token.Token
Value int64
}
func (il *IntegerLiteral) expressionNode() {}
func (il *IntegerLiteral) TokenLiteral() string { return il.Token.Literal }
func (il *IntegerLiteral) String() string { return il.Token.Literal }
type PrefixExpression struct {
Token token.Token
Operator string
Right Expression
}
func (pe *PrefixExpression) expressionNode() {}
func (pe *PrefixExpression) TokenLiteral() string { return pe.Token.Literal }
func (pe *PrefixExpression) String() string {
var out bytes.Buffer
out.WriteString("(")
out.WriteString(pe.Operator)
out.WriteString(pe.Right.String())
out.WriteString(")")
return out.String()
}
type InfixExpression struct {
Token token.Token
Left Expression
Operator string
Right Expression
}
func (oe *InfixExpression) expressionNode() {}
func (oe *InfixExpression) TokenLiteral() string { return oe.Token.Literal }
func (oe *InfixExpression) String() string {
var out bytes.Buffer
out.WriteString("(")
out.WriteString(oe.Left.String())
out.WriteString(" " + oe.Operator + " ")
out.WriteString(oe.Right.String())
out.WriteString(")")
return out.String()
}
type Boolean struct {
Token token.Token
Value bool
}
func (b *Boolean) expressionNode() {}
func (b *Boolean) TokenLiteral() string { return b.Token.Literal }
func (b *Boolean) String() string { return b.Token.Literal }
type IfExpression struct {
Token token.Token
Condition Expression
Consequence *BlockStatement
Alternative *BlockStatement
}
func (ie *IfExpression) expressionNode() {}
func (ie *IfExpression) TokenLiteral() string { return ie.Token.Literal }
func (ie *IfExpression) String() string {
var out bytes.Buffer
out.WriteString("kama")
out.WriteString(ie.Condition.String())
out.WriteString(" ")
out.WriteString(ie.Consequence.String())
if ie.Alternative != nil {
out.WriteString("sivyo")
out.WriteString(ie.Alternative.String())
}
return out.String()
}
type BlockStatement struct {
Token token.Token
Statements []Statement
}
func (bs *BlockStatement) statementNode() {}
func (bs *BlockStatement) TokenLiteral() string { return bs.Token.Literal }
func (bs *BlockStatement) String() string {
var out bytes.Buffer
for _, s := range bs.Statements {
out.WriteString(s.String())
}
return out.String()
}
type FunctionLiteral struct {
Token token.Token
Name string
Parameters []*Identifier
Defaults map[string]Expression
Body *BlockStatement
}
func (fl *FunctionLiteral) expressionNode() {}
func (fl *FunctionLiteral) TokenLiteral() string { return fl.Token.Literal }
func (fl *FunctionLiteral) String() string {
var out bytes.Buffer
params := []string{}
for _, p := range fl.Parameters {
params = append(params, p.String())
}
out.WriteString(fl.TokenLiteral())
out.WriteString("(")
out.WriteString(strings.Join(params, ", "))
out.WriteString(") ")
out.WriteString(fl.Body.String())
return out.String()
}
type CallExpression struct {
Token token.Token
Function Expression // can be Identifier or FunctionLiteral
Arguments []Expression
}
func (ce *CallExpression) expressionNode() {}
func (ce *CallExpression) TokenLiteral() string { return ce.Token.Literal }
func (ce *CallExpression) String() string {
var out bytes.Buffer
args := []string{}
for _, a := range ce.Arguments {
args = append(args, a.String())
}
out.WriteString(ce.Function.String())
out.WriteString("(")
out.WriteString(strings.Join(args, ", "))
out.WriteString(")")
return out.String()
}
type StringLiteral struct {
Token token.Token
Value string
}
func (sl *StringLiteral) expressionNode() {}
func (sl *StringLiteral) TokenLiteral() string { return sl.Token.Literal }
func (sl *StringLiteral) String() string { return sl.Token.Literal }
type ArrayLiteral struct {
Token token.Token
Elements []Expression
}
func (al *ArrayLiteral) expressionNode() {}
func (al *ArrayLiteral) TokenLiteral() string { return al.Token.Literal }
func (al *ArrayLiteral) String() string {
var out bytes.Buffer
elements := []string{}
for _, el := range al.Elements {
elements = append(elements, el.String())
}
out.WriteString("[")
out.WriteString(strings.Join(elements, ", "))
out.WriteString("]")
return out.String()
}
type IndexExpression struct {
Token token.Token
Left Expression
Index Expression
}
func (ie *IndexExpression) expressionNode() {}
func (ie *IndexExpression) TokenLiteral() string { return ie.Token.Literal }
func (ie *IndexExpression) String() string {
var out bytes.Buffer
out.WriteString("(")
out.WriteString(ie.Left.String())
out.WriteString("[")
out.WriteString(ie.Index.String())
out.WriteString("])")
return out.String()
}
type DictLiteral struct {
Token token.Token
Pairs map[Expression]Expression
}
func (dl *DictLiteral) expressionNode() {}
func (dl *DictLiteral) TokenLiteral() string { return dl.Token.Literal }
func (dl *DictLiteral) String() string {
var out bytes.Buffer
pairs := []string{}
for key, value := range dl.Pairs {
pairs = append(pairs, key.String()+":"+value.String())
}
out.WriteString("(")
out.WriteString(strings.Join(pairs, ", "))
out.WriteString("}")
return out.String()
}
type Assign struct {
Token token.Token
Name *Identifier
Value Expression
}
func (ae *Assign) expressionNode() {}
func (ae *Assign) TokenLiteral() string { return ae.Token.Literal }
func (ae *Assign) String() string {
var out bytes.Buffer
out.WriteString(ae.Name.String())
out.WriteString(ae.TokenLiteral())
out.WriteString(ae.Value.String())
return out.String()
}
type AssignEqual struct {
Token token.Token
Left *Identifier
Value Expression
}
func (ae *AssignEqual) expressionNode() {}
func (ae *AssignEqual) TokenLiteral() string { return ae.Token.Literal }
func (ae *AssignEqual) String() string {
var out bytes.Buffer
out.WriteString(ae.Left.String())
out.WriteString(ae.TokenLiteral())
out.WriteString(ae.Value.String())
return out.String()
}
type AssignmentExpression struct {
Token token.Token
Left Expression
Value Expression
}
func (ae *AssignmentExpression) expressionNode() {}
func (ae *AssignmentExpression) TokenLiteral() string { return ae.Token.Literal }
func (ae *AssignmentExpression) String() string {
var out bytes.Buffer
out.WriteString(ae.Left.String())
out.WriteString(ae.TokenLiteral())
out.WriteString(ae.Value.String())
return out.String()
}
type WhileExpression struct {
Token token.Token
Condition Expression
Consequence *BlockStatement
}
func (we *WhileExpression) expressionNode() {}
func (we *WhileExpression) TokenLiteral() string { return we.Token.Literal }
func (we *WhileExpression) String() string {
var out bytes.Buffer
out.WriteString("wakati")
out.WriteString(we.Condition.String())
out.WriteString(" ")
out.WriteString(we.Consequence.String())
return out.String()
}
type Null struct {
Token token.Token
}
func (n *Null) expressionNode() {}
func (n *Null) TokenLiteral() string { return n.Token.Literal }
func (n *Null) String() string { return n.Token.Literal }
type Break struct {
Statement
Token token.Token // the 'break' token
}
func (b *Break) expressionNode() {}
func (b *Break) TokenLiteral() string { return b.Token.Literal }
func (b *Break) String() string { return b.Token.Literal }
type Continue struct {
Statement
Token token.Token // the 'continue' token
}
func (c *Continue) expressionNode() {}
func (c *Continue) TokenLiteral() string { return c.Token.Literal }
func (c *Continue) String() string { return c.Token.Literal }
type PostfixExpression struct {
Token token.Token
Operator string
}
func (pe *PostfixExpression) expressionNode() {}
func (pe *PostfixExpression) TokenLiteral() string { return pe.Token.Literal }
func (pe *PostfixExpression) String() string {
var out bytes.Buffer
out.WriteString("(")
out.WriteString(pe.Token.Literal)
out.WriteString(pe.Operator)
out.WriteString(")")
return out.String()
}
type FloatLiteral struct {
Token token.Token
Value float64
}
func (fl *FloatLiteral) expressionNode() {}
func (fl *FloatLiteral) TokenLiteral() string { return fl.Token.Literal }
func (fl *FloatLiteral) String() string { return fl.Token.Literal }
type For struct {
Token token.Token
Identifier string // "i"
StarterName *Identifier // i = 0
StarterValue Expression
Closer Expression // i++
Condition Expression // i < 1
Block *BlockStatement
}
type ForIn struct {
Token token.Token
Key string
Value string
Iterable Expression
Block *BlockStatement
}
func (fi *ForIn) expressionNode() {}
func (fi *ForIn) TokenLiteral() string { return fi.Token.Literal }
func (fi *ForIn) String() string {
var out bytes.Buffer
out.WriteString("kwa ")
if fi.Key != "" {
out.WriteString(fi.Key + ", ")
}
out.WriteString(fi.Value + " ")
out.WriteString("ktk ")
out.WriteString(fi.Iterable.String() + " {\n")
out.WriteString("\t" + fi.Block.String())
out.WriteString("\n}")
return out.String()
}
type CaseExpression struct {
Token token.Token
Default bool
Expr []Expression
Block *BlockStatement
}
func (ce *CaseExpression) expressionNode() {}
func (ce *CaseExpression) TokenLiteral() string { return ce.Token.Literal }
func (ce *CaseExpression) String() string {
var out bytes.Buffer
if ce.Default {
out.WriteString("kawaida ")
} else {
out.WriteString("ikiwa ")
tmp := []string{}
for _, exp := range ce.Expr {
tmp = append(tmp, exp.String())
}
out.WriteString(strings.Join(tmp, ","))
}
out.WriteString(ce.Block.String())
return out.String()
}
type SwitchExpression struct {
Token token.Token
Value Expression
Choices []*CaseExpression
}
func (se *SwitchExpression) expressionNode() {}
func (se *SwitchExpression) TokenLiteral() string { return se.Token.Literal }
func (se *SwitchExpression) String() string {
var out bytes.Buffer
out.WriteString("\nbadili (")
out.WriteString(se.Value.String())
out.WriteString(")\n{\n")
for _, tmp := range se.Choices {
if tmp != nil {
out.WriteString(tmp.String())
}
}
out.WriteString("}\n")
return out.String()
}
type MethodExpression struct {
Token token.Token
Object Expression
Method Expression
Arguments []Expression
Defaults map[string]Expression
}
func (me *MethodExpression) expressionNode() {}
func (me *MethodExpression) TokenLiteral() string { return me.Token.Literal }
func (me *MethodExpression) String() string {
var out bytes.Buffer
out.WriteString(me.Object.String())
out.WriteString(".")
out.WriteString(me.Method.String())
return out.String()
}
type Import struct {
Token token.Token
Identifiers map[string]*Identifier
}
func (i *Import) expressionNode() {}
func (i *Import) TokenLiteral() string { return i.Token.Literal }
func (i *Import) String() string {
var out bytes.Buffer
out.WriteString("tumia ")
for k := range i.Identifiers {
out.WriteString(k + " ")
}
return out.String()
}
type PackageBlock struct {
Token token.Token
Statements []Statement
}
func (pb *PackageBlock) statementNode() {}
func (pb *PackageBlock) TokenLiteral() string { return pb.Token.Literal }
func (pb *PackageBlock) String() string {
var out bytes.Buffer
for _, s := range pb.Statements {
out.WriteString(s.String())
}
return out.String()
}
type Package struct {
Token token.Token
Name *Identifier
Block *BlockStatement
}
func (p *Package) expressionNode() {}
func (p *Package) TokenLiteral() string { return p.Token.Literal }
func (p *Package) String() string {
var out bytes.Buffer
out.WriteString("pakeji " + p.Name.Value + "\n")
out.WriteString("::\n")
for _, s := range p.Block.Statements {
out.WriteString(s.String())
}
out.WriteString("\n::")
return out.String()
}
type At struct {
Token token.Token
}
func (a *At) expressionNode() {}
func (a *At) TokenLiteral() string { return a.Token.Literal }
func (a *At) String() string { return "@" }
type PropertyAssignment struct {
Token token.Token // the '=' token
Name *PropertyExpression
Value Expression
}
func (pa *PropertyAssignment) expressionNode() {}
func (pa *PropertyAssignment) TokenLiteral() string { return pa.Token.Literal }
func (pa *PropertyAssignment) String() string { return "Ngl I'm tired" }
type PropertyExpression struct {
Expression
Token token.Token // The . token
Object Expression
Property Expression
}
func (pe *PropertyExpression) expressionNode() {}
func (pe *PropertyExpression) TokenLiteral() string { return pe.Token.Literal }
func (pe *PropertyExpression) String() string { return "Ngl I'm tired part two" }
================================================
FILE: ast/ast_test.go
================================================
package ast
import (
"testing"
"github.com/NuruProgramming/Nuru/token"
)
func TestString(t *testing.T) {
program := &Program{
Statements: []Statement{
&LetStatement{
Token: token.Token{Type: token.LET, Literal: "fanya"},
Name: &Identifier{
Token: token.Token{Type: token.IDENT, Literal: "myVar"},
Value: "myVar",
},
Value: &Identifier{
Token: token.Token{Type: token.IDENT, Literal: "anotherVar"},
Value: "anotherVar",
},
},
},
}
if program.String() != "fanya myVar = anotherVar;" {
t.Errorf("program.String() wrong. got=%q", program.String())
}
}
================================================
FILE: evaluator/assign.go
================================================
package evaluator
import (
"github.com/NuruProgramming/Nuru/ast"
"github.com/NuruProgramming/Nuru/object"
)
func evalAssign(node *ast.Assign, env *object.Environment) object.Object {
val := Eval(node.Value, env)
if isError(val) {
return val
}
obj := env.Set(node.Name.Value, val)
return obj
}
================================================
FILE: evaluator/assignEqual.go
================================================
package evaluator
import (
"strings"
"github.com/NuruProgramming/Nuru/ast"
"github.com/NuruProgramming/Nuru/object"
)
func evalAssignEqual(node *ast.AssignEqual, env *object.Environment) object.Object {
left := Eval(node.Left, env)
if isError(left) {
return left
}
value := Eval(node.Value, env)
if isError(value) {
return value
}
switch node.Token.Literal {
case "+=":
switch arg := left.(type) {
case *object.Integer:
switch val := value.(type) {
case *object.Integer:
v := arg.Value + val.Value
return env.Set(node.Left.Token.Literal, &object.Integer{Value: v})
case *object.Float:
v := float64(arg.Value) + val.Value
return env.Set(node.Left.Token.Literal, &object.Float{Value: v})
default:
return newError("Mstari %d: Huwezi kutumia '+=' kujumlisha %v na %v", node.Token.Line, arg.Type(), val.Type())
}
case *object.Float:
switch val := value.(type) {
case *object.Integer:
v := arg.Value + float64(val.Value)
return env.Set(node.Left.Token.Literal, &object.Float{Value: v})
case *object.Float:
v := arg.Value + val.Value
return env.Set(node.Left.Token.Literal, &object.Float{Value: v})
default:
return newError("Mstari %d: Huwezi kutumia '+=' kujumlisha %v na %v", node.Token.Line, arg.Type(), val.Type())
}
case *object.String:
switch val := value.(type) {
case *object.String:
v := arg.Value + val.Value
return env.Set(node.Left.Token.Literal, &object.String{Value: v})
default:
return newError("Mstari %d: Huwezi kutumia '+=' kwa %v na %v", node.Token.Line, arg.Type(), val.Type())
}
default:
return newError("Mstari %d: Huwezi kutumia '+=' na %v", node.Token.Line, arg.Type())
}
case "-=":
switch arg := left.(type) {
case *object.Integer:
switch val := value.(type) {
case *object.Integer:
v := arg.Value - val.Value
return env.Set(node.Left.Token.Literal, &object.Integer{Value: v})
case *object.Float:
v := float64(arg.Value) - val.Value
return env.Set(node.Left.Token.Literal, &object.Float{Value: v})
default:
return newError("Mstari %d: Huwezi kutumia '-=' kujumlisha %v na %v", node.Token.Line, arg.Type(), val.Type())
}
case *object.Float:
switch val := value.(type) {
case *object.Integer:
v := arg.Value - float64(val.Value)
return env.Set(node.Left.Token.Literal, &object.Float{Value: v})
case *object.Float:
v := arg.Value - val.Value
return env.Set(node.Left.Token.Literal, &object.Float{Value: v})
default:
return newError("Mstari %d: Huwezi kutumia '-=' kujumlisha %v na %v", node.Token.Line, arg.Type(), val.Type())
}
default:
return newError("Mstari %d: Huwezi kutumia '-=' na %v", node.Token.Line, arg.Type())
}
case "*=":
switch arg := left.(type) {
case *object.Integer:
switch val := value.(type) {
case *object.Integer:
v := arg.Value * val.Value
return env.Set(node.Left.Token.Literal, &object.Integer{Value: v})
case *object.Float:
v := float64(arg.Value) * val.Value
return env.Set(node.Left.Token.Literal, &object.Float{Value: v})
case *object.String:
v := strings.Repeat(val.Value, int(arg.Value))
return env.Set(node.Left.Token.Literal, &object.String{Value: v})
default:
return newError("Mstari %d: Huwezi kutumia '*=' kujumlisha %v na %v", node.Token.Line, arg.Type(), val.Type())
}
case *object.Float:
switch val := value.(type) {
case *object.Integer:
v := arg.Value * float64(val.Value)
return env.Set(node.Left.Token.Literal, &object.Float{Value: v})
case *object.Float:
v := arg.Value * val.Value
return env.Set(node.Left.Token.Literal, &object.Float{Value: v})
default:
return newError("Mstari %d: Huwezi kutumia '*=' kujumlisha %v na %v", node.Token.Line, arg.Type(), val.Type())
}
case *object.String:
switch val := value.(type) {
case *object.Integer:
v := strings.Repeat(arg.Value, int(val.Value))
return env.Set(node.Left.Token.Literal, &object.String{Value: v})
default:
return newError("Mstari %d: Huwezi kutumia '+=' kwa %v na %v", node.Token.Line, arg.Type(), val.Type())
}
default:
return newError("Mstari %d: Huwezi kutumia '*=' na %v", node.Token.Line, arg.Type())
}
case "/=":
switch arg := left.(type) {
case *object.Integer:
switch val := value.(type) {
case *object.Integer:
v := arg.Value / val.Value
return env.Set(node.Left.Token.Literal, &object.Integer{Value: v})
case *object.Float:
v := float64(arg.Value) / val.Value
return env.Set(node.Left.Token.Literal, &object.Float{Value: v})
default:
return newError("Mstari %d: Huwezi kutumia '/=' kujumlisha %v na %v", node.Token.Line, arg.Type(), val.Type())
}
case *object.Float:
switch val := value.(type) {
case *object.Integer:
v := arg.Value / float64(val.Value)
return env.Set(node.Left.Token.Literal, &object.Float{Value: v})
case *object.Float:
v := arg.Value / val.Value
return env.Set(node.Left.Token.Literal, &object.Float{Value: v})
default:
return newError("Mstari %d: Huwezi kutumia '/=' kujumlisha %v na %v", node.Token.Line, arg.Type(), val.Type())
}
default:
return newError("Mstari %d: Huwezi kutumia '/=' na %v", node.Token.Line, arg.Type())
}
default:
return newError("Mstari %d: Operesheni Haifahamiki %s", node.Token.Line, node.Token.Literal)
}
}
================================================
FILE: evaluator/at.go
================================================
package evaluator
import (
"github.com/NuruProgramming/Nuru/ast"
"github.com/NuruProgramming/Nuru/object"
)
func evalAt(node *ast.At, env *object.Environment) object.Object {
if at, ok := env.Get("@"); ok {
return at
}
return newError("Iko nje ya scope")
}
================================================
FILE: evaluator/bang.go
================================================
package evaluator
import "github.com/NuruProgramming/Nuru/object"
func evalBangOperatorExpression(right object.Object) object.Object {
switch right {
case TRUE:
return FALSE
case FALSE:
return TRUE
case NULL:
return TRUE
default:
return FALSE
}
}
================================================
FILE: evaluator/block.go
================================================
package evaluator
import (
"github.com/NuruProgramming/Nuru/ast"
"github.com/NuruProgramming/Nuru/object"
)
func evalBlockStatement(block *ast.BlockStatement, env *object.Environment) object.Object {
var result object.Object
for _, statement := range block.Statements {
result = Eval(statement, env)
if result != nil {
rt := result.Type()
if rt == object.RETURN_VALUE_OBJ || rt == object.ERROR_OBJ || rt == object.CONTINUE_OBJ || rt == object.BREAK_OBJ {
return result
}
}
}
return result
}
================================================
FILE: evaluator/builtins.go
================================================
//go:build !js || !wasm
package evaluator
import (
"bufio"
"fmt"
"io"
"os"
"strings"
"github.com/NuruProgramming/Nuru/object"
)
var builtins = map[string]*object.Builtin{
"jaza": {
Fn: func(args ...object.Object) object.Object {
if len(args) > 1 {
return newError("Samahani, kiendesha hiki kinapokea hoja 0 au 1, wewe umeweka %d", len(args))
}
if len(args) > 0 && args[0].Type() != object.STRING_OBJ {
return newError(fmt.Sprintf(`Tafadhali tumia alama ya nukuu: "%s"`, args[0].Inspect()))
}
if len(args) == 1 {
prompt := args[0].(*object.String).Value
fmt.Fprint(os.Stdout, prompt)
}
buffer := bufio.NewReader(os.Stdin)
line, _, err := buffer.ReadLine()
if err != nil && err != io.EOF {
return newError("Nimeshindwa kusoma uliyo yajaza")
}
return &object.String{Value: string(line)}
},
},
"andika": {
Fn: func(args ...object.Object) object.Object {
if len(args) == 0 {
fmt.Println("")
} else {
var arr []string
for _, arg := range args {
if arg == nil {
return newError("Hauwezi kufanya operesheni hii")
}
arr = append(arr, arg.Inspect())
}
str := strings.Join(arr, " ")
fmt.Println(str)
}
return nil
},
},
"_andika": {
Fn: func(args ...object.Object) object.Object {
if len(args) == 0 {
return &object.String{Value: "\n"}
} else {
var arr []string
for _, arg := range args {
if arg == nil {
return newError("Hauwezi kufanya operesheni hii")
}
arr = append(arr, arg.Inspect())
}
str := strings.Join(arr, " ")
return &object.String{Value: str}
}
},
},
}
func init(){
for name, builtin := range commonBuiltins{
builtins[name]=builtin
}
}
================================================
FILE: evaluator/builtins_common.go
================================================
package evaluator
import (
"fmt"
"os"
"strings"
"github.com/NuruProgramming/Nuru/object"
)
var commonBuiltins = map[string]*object.Builtin{
"_andika": {
Fn: func(args ...object.Object) object.Object {
if len(args) == 0 {
return &object.String{Value: "\n"}
} else {
var arr []string
for _, arg := range args {
if arg == nil {
return newError("Hauwezi kufanya operesheni hii")
}
arr = append(arr, arg.Inspect())
}
str := strings.Join(arr, " ")
return &object.String{Value: str}
}
},
},
"aina": {
Fn: func(args ...object.Object) object.Object {
if len(args) != 1 {
return newError("Samahani, tunahitaji hoja 1, wewe umeweka %d", len(args))
}
return &object.String{Value: string(args[0].Type())}
},
},
"fungua": {
Fn: func(args ...object.Object) object.Object {
if len(args) != 1 {
return newError("Samahani, tunahitaji hoja 1, wewe umeweka %d", len(args))
}
filename := args[0].(*object.String).Value
file, err := os.ReadFile(filename)
if err != nil {
return &object.Error{Message: "Tumeshindwa kusoma faili au faili halipo"}
}
return &object.File{Filename: filename, Content: string(file)}
},
},
"mfululizo": {
Fn: func(args ...object.Object) object.Object {
if len(args) < 1 || len(args) > 3 {
return newError("Samahani, mfululizo inahitaji hoja 1 hadi 3, wewe umeweka %d", len(args))
}
var start, end, step int64
var err error
switch len(args) {
case 1:
end, err = getIntValue(args[0])
if err != nil {
return newError("Hoja lazima iwe nambari nzima")
}
start, step = 0, 1
case 2:
start, err = getIntValue(args[0])
if err != nil {
return newError("Hoja ya kwanza lazima iwe nambari nzima")
}
end, err = getIntValue(args[1])
if err != nil {
return newError("Hoja ya pili lazima iwe nambari nzima")
}
step = 1
case 3:
start, err = getIntValue(args[0])
if err != nil {
return newError("Hoja ya kwanza lazima iwe nambari nzima")
}
end, err = getIntValue(args[1])
if err != nil {
return newError("Hoja ya pili lazima iwe nambari nzima")
}
step, err = getIntValue(args[2])
if err != nil {
return newError("Hoja ya tatu lazima iwe nambari nzima")
}
if step == 0 {
return newError("Hatua haiwezi kuwa sifuri")
}
}
elements := []object.Object{}
for i := start; (step > 0 && i < end) || (step < 0 && i > end); i += step {
elements = append(elements, &object.Integer{Value: i})
}
return &object.Array{Elements: elements}
},
},
"badilisha": {
Fn: func(args ...object.Object) object.Object {
if len(args) != 2 {
return newError("Samahani, badili inahitaji hoja 2, wewe umeweka %d", len(args))
}
value := args[0]
targetType := args[1]
if targetType.Type() != object.STRING_OBJ {
return newError("Aina ya lengo lazima iwe neno")
}
targetTypeStr := targetType.(*object.String).Value
switch targetTypeStr {
case "NAMBA":
return convertToInteger(value)
case "DESIMALI":
return convertToFloat(value)
case "NENO":
return convertToString(value)
case "BOOLEAN":
return convertToBoolean(value)
default:
return newError("Aina isiyojulikana: %s", targetTypeStr)
}
},
},
"namba": {
Fn: func(args ...object.Object) object.Object {
if len(args) != 1 {
return newError("Samahani, namba inahitaji hoja 1, wewe umeweka %d", len(args))
}
value := args[0]
return convertToInteger(value)
},
},
"tungo": {
Fn: func(args ...object.Object) object.Object {
if len(args) != 1 {
return newError("Samahani, tungo inahitaji hoja 1, wewe umeweka %d", len(args))
}
value := args[0]
return convertToString(value)
},
},
// "jumla": {
// Fn: func(args ...object.Object) object.Object {
// if len(args) != 1 {
// return newError("Hoja hazilingani, tunahitaji=1, tumepewa=%d", len(args))
// }
// switch arg := args[0].(type) {
// case *object.Array:
// var sums float64
// for _, num := range arg.Elements {
// if num.Type() != object.INTEGER_OBJ && num.Type() != object.FLOAT_OBJ {
// return newError("Samahani namba tu zinahitajika")
// } else {
// if num.Type() == object.INTEGER_OBJ {
// no, _ := strconv.Atoi(num.Inspect())
// floatnum := float64(no)
// sums += floatnum
// } else if num.Type() == object.FLOAT_OBJ {
// no, _ := strconv.ParseFloat(num.Inspect(), 64)
// sums += no
// }
// }
// }
// if math.Mod(sums, 1) == 0 {
// return &object.Integer{Value: int64(sums)}
// }
// return &object.Float{Value: float64(sums)}
// default:
// return newError("Samahani, hii function haitumiki na %s", args[0].Type())
// }
// },
// },
}
func getIntValue(obj object.Object) (int64, error) {
switch obj := obj.(type) {
case *object.Integer:
return obj.Value, nil
default:
return 0, fmt.Errorf("expected integer, got %T", obj)
}
}
================================================
FILE: evaluator/builtins_wasm.go
================================================
//go:build wasm && js
// Modified version with of the builtins.go file with browser friendly versions of functions.
package evaluator
import (
"fmt"
"strings"
"github.com/NuruProgramming/Nuru/object"
"syscall/js"
)
var builtins = map[string]*object.Builtin{
"jaza": {
Fn: func(args ...object.Object) object.Object {
if len(args) > 1 {
return newError("Samahani, kiendesha hiki kinapokea hoja 0 au 1, wewe umeweka %d", len(args))
}
if len(args) == 1 && args[0].Type() != object.STRING_OBJ {
return newError(fmt.Sprintf(`Tafadhali tumia alama ya nukuu: "%s"`, args[0].Inspect()))
}
// Get the window.prompt function
jsPromptFunction := js.Global().Get("prompt")
if jsPromptFunction.Type() != js.TypeFunction {
return newError("prompt function not found")
}
// invoke it!!
var result js.Value
if len(args) == 0 {
result = jsPromptFunction.Invoke()
} else {
result = jsPromptFunction.Invoke(args[0].Inspect())
}
if result.String() == ""|| result.String() == "null" {
return newError("Nimeshindwa kusoma uliyo yajaza")
}
return &object.String{Value: string(result.String())}
},
},
"andika": {
Fn: func(args ...object.Object) object.Object {
jsOutputReceiverFunction := js.Global().Get("nuruOutputReceiver")
if len(args) == 0 {
jsOutputReceiverFunction.Invoke("")
} else {
var arr []string
for _, arg := range args {
if arg == nil {
return newError("Hauwezi kufanya operesheni hii")
}
arr = append(arr, arg.Inspect())
}
str := strings.Join(arr, " ")
jsOutputReceiverFunction.Invoke(str) // pipe output to js land
}
return nil
},
},
}
func init(){
for name, builtin := range commonBuiltins{
builtins[name]=builtin
}
}
================================================
FILE: evaluator/call.go
================================================
package evaluator
import (
"github.com/NuruProgramming/Nuru/ast"
"github.com/NuruProgramming/Nuru/object"
)
func evalCall(node *ast.CallExpression, env *object.Environment) object.Object {
function := Eval(node.Function, env)
if isError(function) {
return function
}
var args []object.Object
switch fn := function.(type) {
case *object.Function:
args = evalArgsExpressions(node, fn, env)
case *object.Package:
obj, ok := fn.Scope.Get("andaa")
if !ok {
return newError("Pakeji haina 'andaa'")
}
args = evalArgsExpressions(node, obj.(*object.Function), env)
default:
args = evalExpressions(node.Arguments, env)
}
if len(args) == 1 && isError(args[0]) {
return args[0]
}
return applyFunction(function, args, node.Token.Line)
}
func evalArgsExpressions(node *ast.CallExpression, fn *object.Function, env *object.Environment) []object.Object {
argsList := &object.Array{}
argsHash := &object.Dict{}
argsHash.Pairs = make(map[object.HashKey]object.DictPair)
for _, exprr := range node.Arguments {
switch exp := exprr.(type) {
case *ast.Assign:
val := Eval(exp.Value, env)
if isError(val) {
return []object.Object{val}
}
var keyHash object.HashKey
key := &object.String{Value: exp.Name.Value}
keyHash = key.HashKey()
pair := object.DictPair{Key: key, Value: val}
argsHash.Pairs[keyHash] = pair
default:
evaluated := Eval(exp, env)
if isError(evaluated) {
return []object.Object{evaluated}
}
argsList.Elements = append(argsList.Elements, evaluated)
}
}
var result []object.Object
var params = map[string]bool{}
for _, exp := range fn.Parameters {
params[exp.Value] = true
if len(argsList.Elements) > 0 {
result = append(result, argsList.Elements[0])
argsList.Elements = argsList.Elements[1:]
} else {
keyParam := &object.String{Value: exp.Value}
keyParamHash := keyParam.HashKey()
if valParam, ok := argsHash.Pairs[keyParamHash]; ok {
result = append(result, valParam.Value)
delete(argsHash.Pairs, keyParamHash)
} else {
if _e, _ok := fn.Defaults[exp.Value]; _ok {
evaluated := Eval(_e, env)
if isError(evaluated) {
return []object.Object{evaluated}
}
result = append(result, evaluated)
} else {
return []object.Object{&object.Error{Message: "Tumekosa Hoja"}}
}
}
}
}
for _, pair := range argsHash.Pairs {
if _, ok := params[pair.Key.(*object.String).Value]; ok {
return []object.Object{&object.Error{Message: "Tumepewa hoja nyingi kwa parameter moja"}}
}
}
return result
}
================================================
FILE: evaluator/dict.go
================================================
package evaluator
import (
"github.com/NuruProgramming/Nuru/ast"
"github.com/NuruProgramming/Nuru/object"
)
func evalDictLiteral(node *ast.DictLiteral, env *object.Environment) object.Object {
pairs := make(map[object.HashKey]object.DictPair)
for keyNode, valueNode := range node.Pairs {
key := Eval(keyNode, env)
if isError(key) {
return key
}
hashKey, ok := key.(object.Hashable)
if !ok {
return newError("Mstari %d: Hashing imeshindikana: %s", node.Token.Line, key.Type())
}
value := Eval(valueNode, env)
if isError(value) {
return value
}
hashed := hashKey.HashKey()
pairs[hashed] = object.DictPair{Key: key, Value: value}
}
return &object.Dict{Pairs: pairs}
}
================================================
FILE: evaluator/error_handler.go
================================================
package evaluator
import (
"fmt"
"github.com/NuruProgramming/Nuru/object"
)
func newError(format string, a ...interface{}) *object.Error {
return &object.Error{Message: fmt.Sprintf(format, a...)}
}
================================================
FILE: evaluator/evaluator.go
================================================
package evaluator
import (
"github.com/NuruProgramming/Nuru/ast"
"github.com/NuruProgramming/Nuru/object"
)
var (
NULL = &object.Null{}
TRUE = &object.Boolean{Value: true}
FALSE = &object.Boolean{Value: false}
BREAK = &object.Break{}
CONTINUE = &object.Continue{}
)
func Eval(node ast.Node, env *object.Environment) object.Object {
switch node := node.(type) {
case *ast.Program:
return evalProgram(node, env)
case *ast.ExpressionStatement:
return Eval(node.Expression, env)
case *ast.IntegerLiteral:
return &object.Integer{Value: node.Value}
case *ast.FloatLiteral:
return &object.Float{Value: node.Value}
case *ast.Boolean:
return nativeBoolToBooleanObject(node.Value)
case *ast.PrefixExpression:
right := Eval(node.Right, env)
if isError(right) {
return right
}
return evalPrefixExpression(node.Operator, right, node.Token.Line)
case *ast.InfixExpression:
left := Eval(node.Left, env)
if isError(left) {
return left
}
right := Eval(node.Right, env)
if isError(right) && right != nil {
return right
}
return evalInfixExpression(node.Operator, left, right, node.Token.Line)
case *ast.PostfixExpression:
return evalPostfixExpression(env, node.Operator, node)
case *ast.BlockStatement:
return evalBlockStatement(node, env)
case *ast.IfExpression:
return evalIfExpression(node, env)
case *ast.ReturnStatement:
val := Eval(node.ReturnValue, env)
if isError(val) {
return val
}
return &object.ReturnValue{Value: val}
case *ast.LetStatement:
val := Eval(node.Value, env)
if isError(val) {
return val
}
env.Set(node.Name.Value, val)
case *ast.Identifier:
return evalIdentifier(node, env)
case *ast.FunctionLiteral:
return evalFunction(node, env)
case *ast.MethodExpression:
return evalMethodExpression(node, env)
case *ast.Import:
return evalImport(node, env)
case *ast.CallExpression:
return evalCall(node, env)
case *ast.StringLiteral:
return &object.String{Value: node.Value}
case *ast.At:
return evalAt(node, env)
case *ast.ArrayLiteral:
elements := evalExpressions(node.Elements, env)
if len(elements) == 1 && isError(elements[0]) {
return elements[0]
}
return &object.Array{Elements: elements}
case *ast.IndexExpression:
left := Eval(node.Left, env)
if isError(left) {
return left
}
index := Eval(node.Index, env)
if isError(index) {
return index
}
return evalIndexExpression(left, index, node.Token.Line)
case *ast.DictLiteral:
return evalDictLiteral(node, env)
case *ast.WhileExpression:
return evalWhileExpression(node, env)
case *ast.Break:
return evalBreak(node)
case *ast.Continue:
return evalContinue(node)
case *ast.SwitchExpression:
return evalSwitchStatement(node, env)
case *ast.Null:
return NULL
// case *ast.For:
// return evalForExpression(node, env)
case *ast.ForIn:
return evalForInExpression(node, env, node.Token.Line)
case *ast.Package:
return evalPackage(node, env)
case *ast.PropertyExpression:
return evalPropertyExpression(node, env)
case *ast.PropertyAssignment:
val := Eval(node.Value, env)
if isError(val) {
return val
}
return evalPropertyAssignment(node.Name, val, env)
case *ast.Assign:
return evalAssign(node, env)
case *ast.AssignEqual:
return evalAssignEqual(node, env)
case *ast.AssignmentExpression:
left := Eval(node.Left, env)
if isError(left) {
return left
}
value := Eval(node.Value, env)
if isError(value) {
return value
}
// This is an easy way to assign operators like +=, -= etc
// for index expressions (arrays and dicts) where applicable
op := node.Token.Literal
if len(op) >= 2 {
op = op[:len(op)-1]
value = evalInfixExpression(op, left, value, node.Token.Line)
if isError(value) {
return value
}
}
if ident, ok := node.Left.(*ast.Identifier); ok {
env.Set(ident.Value, value)
} else if ie, ok := node.Left.(*ast.IndexExpression); ok {
obj := Eval(ie.Left, env)
if isError(obj) {
return obj
}
if array, ok := obj.(*object.Array); ok {
index := Eval(ie.Index, env)
if isError(index) {
return index
}
if idx, ok := index.(*object.Integer); ok {
if int(idx.Value) >= len(array.Elements) {
return newError("Index imezidi idadi ya elements")
}
array.Elements[idx.Value] = value
} else {
return newError("Hauwezi kufanya operesheni hii na %#v", index)
}
} else if hash, ok := obj.(*object.Dict); ok {
key := Eval(ie.Index, env)
if isError(key) {
return key
}
if hashKey, ok := key.(object.Hashable); ok {
hashed := hashKey.HashKey()
hash.Pairs[hashed] = object.DictPair{Key: key, Value: value}
} else {
return newError("Hauwezi kufanya operesheni hii na %T", key)
}
} else {
return newError("%T haifanyi operesheni hii", obj)
}
} else {
return newError("Tumia neno kama kibadala, sio %T", left)
}
}
return nil
}
func evalProgram(program *ast.Program, env *object.Environment) object.Object {
var result object.Object
for _, statement := range program.Statements {
result = Eval(statement, env)
switch result := result.(type) {
case *object.ReturnValue:
return result.Value
case *object.Error:
return result
}
}
return result
}
func nativeBoolToBooleanObject(input bool) *object.Boolean {
if input {
return TRUE
}
return FALSE
}
func isTruthy(obj object.Object) bool {
switch obj {
case NULL:
return false
case TRUE:
return true
case FALSE:
return false
default:
return true
}
}
func isError(obj object.Object) bool {
if obj != nil {
return obj.Type() == object.ERROR_OBJ
}
return false
}
func evalExpressions(exps []ast.Expression, env *object.Environment) []object.Object {
var result []object.Object
for _, e := range exps {
evaluated := Eval(e, env)
if isError(evaluated) {
return []object.Object{evaluated}
}
result = append(result, evaluated)
}
return result
}
func applyFunction(fn object.Object, args []object.Object, line int) object.Object {
switch fn := fn.(type) {
case *object.Function:
extendedEnv := extendedFunctionEnv(fn, args)
evaluated := Eval(fn.Body, extendedEnv)
return unwrapReturnValue(evaluated)
case *object.Builtin:
if result := fn.Fn(args...); result != nil {
return result
}
return NULL
case *object.Package:
obj := &object.Instance{
Package: fn,
Env: object.NewEnclosedEnvironment(fn.Env),
}
obj.Env.Set("@", obj)
node, ok := fn.Scope.Get("andaa")
if !ok {
return newError("Hamna andaa kiendesha")
}
node.(*object.Function).Env.Set("@", obj)
applyFunction(node, args, fn.Name.Token.Line)
node.(*object.Function).Env.Del("@")
return obj
default:
if fn != nil {
return newError("Mstari %d: Hiki sio kiendesha: %s", line, fn.Type())
} else {
return newError("Bro how did you even get here??? Contact language maker asap!")
}
}
}
func extendedFunctionEnv(fn *object.Function, args []object.Object) *object.Environment {
env := object.NewEnclosedEnvironment(fn.Env)
for paramIdx, param := range fn.Parameters {
if paramIdx < len(args) {
env.Set(param.Value, args[paramIdx])
}
}
return env
}
func unwrapReturnValue(obj object.Object) object.Object {
if returnValue, ok := obj.(*object.ReturnValue); ok {
return returnValue.Value
}
return obj
}
func evalBreak(node *ast.Break) object.Object {
return BREAK
}
func evalContinue(node *ast.Continue) object.Object {
return CONTINUE
}
// func evalForExpression(fe *ast.For, env *object.Environment) object.Object {
// obj, ok := env.Get(fe.Identifier)
// defer func() { // stay safe and not reassign an existing variable
// if ok {
// env.Set(fe.Identifier, obj)
// }
// }()
// val := Eval(fe.StarterValue, env)
// if isError(val) {
// return val
// }
// env.Set(fe.StarterName.Value, val)
// // err := Eval(fe.Starter, env)
// // if isError(err) {
// // return err
// // }
// for {
// evaluated := Eval(fe.Condition, env)
// if isError(evaluated) {
// return evaluated
// }
// if !isTruthy(evaluated) {
// break
// }
// res := Eval(fe.Block, env)
// if isError(res) {
// return res
// }
// if res.Type() == object.BREAK_OBJ {
// break
// }
// if res.Type() == object.CONTINUE_OBJ {
// err := Eval(fe.Closer, env)
// if isError(err) {
// return err
// }
// continue
// }
// if res.Type() == object.RETURN_VALUE_OBJ {
// return res
// }
// err := Eval(fe.Closer, env)
// if isError(err) {
// return err
// }
// }
// return NULL
// }
func loopIterable(next func() (object.Object, object.Object), env *object.Environment, fi *ast.ForIn) object.Object {
k, v := next()
for k != nil && v != nil {
env.Set(fi.Key, k)
env.Set(fi.Value, v)
res := Eval(fi.Block, env)
if isError(res) {
return res
}
if res != nil {
if res.Type() == object.BREAK_OBJ {
break
}
if res.Type() == object.CONTINUE_OBJ {
k, v = next()
continue
}
if res.Type() == object.RETURN_VALUE_OBJ {
return res
}
}
k, v = next()
}
return NULL
}
================================================
FILE: evaluator/evaluator_test.go
================================================
package evaluator
import (
"fmt"
"testing"
"time"
"github.com/NuruProgramming/Nuru/lexer"
"github.com/NuruProgramming/Nuru/object"
"github.com/NuruProgramming/Nuru/parser"
)
func TestEvalIntegerExpression(t *testing.T) {
tests := []struct {
input string
expected int64
}{
{"5", 5},
{"10", 10},
{"-5", -5},
{"-10", -10},
{"5 + 5 + 5 + 5 - 10", 10},
{"2 * 2 * 2 * 2", 16},
{"2 / 2 + 1", 2},
}
for _, tt := range tests {
evaluated := testEval(tt.input)
testIntegerObject(t, evaluated, tt.expected)
}
}
func TestEvalFloatExpression(t *testing.T) {
tests := []struct {
input string
expected float64
}{
{"2**3", 8.0},
}
for _, tt := range tests {
evaluated := testEval(tt.input)
testFloatObject(t, evaluated, tt.expected)
}
}
func TestEvalBooleanExpression(t *testing.T) {
tests := []struct {
input string
expected bool
}{
{"kweli", true},
{"sikweli", false},
{"1 < 2", true},
{"1 > 2", false},
{"1 > 1", false},
{"1 < 1", false},
{"1 == 1", true},
{"1 != 1", false},
{"1 == 2", false},
{"1 != 2", true},
{"kweli == kweli", true},
{"sikweli == sikweli", true},
{"kweli == sikweli", false},
{"kweli != sikweli", true},
{"sikweli != kweli", true},
{"(1 < 2) == kweli", true},
{"!kweli", false},
{"!sikweli", true},
{"!tupu", true},
{"!'kitu'", false},
{"2 > 1 && 1 < 4", true},
{"2 > 1 && 1 > 4", false},
{"2 < 1 && 1 < 4", false},
{"2 < 1 && 1 > 4", false},
{"5 < 2 || 3 > 2", true},
{"5 == 5 || 4 == 4", true},
{"5 > 2 || 3 < 2", true},
{"5 < 2 || 3 < 2", false},
{"5 >= 2", true},
{"5 <= 2", false},
}
for _, tt := range tests {
evaluated := testEval(tt.input)
testBooleanObject(t, evaluated, tt.expected)
}
}
func TestBangOperator(t *testing.T) {
tests := []struct {
input string
expected bool
}{
{"!kweli", false},
{"!sikweli", true},
{"!5", false},
{"!!kweli", true},
{"!!sikweli", false},
{"!!5", true},
}
for _, tt := range tests {
evaluated := testEval(tt.input)
testBooleanObject(t, evaluated, tt.expected)
}
}
func testEval(input string) object.Object {
l := lexer.New(input)
p := parser.New(l)
program := p.ParseProgram()
env := object.NewEnvironment()
return Eval(program, env)
}
func testIntegerObject(t *testing.T, obj object.Object, expected int64) bool {
result, ok := obj.(*object.Integer)
if !ok {
t.Errorf("Object is not Integer, got=%T(%+v)", obj, obj)
return false
}
if result.Value != expected {
t.Errorf("object has wrong value. got=%d, want=%d", result.Value, expected)
return false
}
return true
}
func testFloatObject(t *testing.T, obj object.Object, expected float64) bool {
result, ok := obj.(*object.Float)
if !ok {
t.Errorf("Object is not Float, got=%T(%+v)", obj, obj)
return false
}
if result.Value != expected {
t.Errorf("object has wrong value. got=%f, want=%f", result.Value, expected)
return false
}
return true
}
func testBooleanObject(t *testing.T, obj object.Object, expected bool) bool {
result, ok := obj.(*object.Boolean)
if !ok {
t.Errorf("object is not Boolean, got=%T(%+v)", obj, obj)
return false
}
if result.Value != expected {
t.Errorf("object has wrong value, got=%t, want=%t", result.Value, expected)
return false
}
return true
}
func TestIfElseExpressions(t *testing.T) {
tests := []struct {
input string
expected interface{}
}{
{"kama (kweli) {10}", 10},
{"kama (sikweli) {10}", nil},
{"kama (1) {10}", 10},
{"kama (1 < 2) {10}", 10},
{"kama (1 > 2) {10}", nil},
{"kama (1 > 2) {10} sivyo {20}", 20},
{"kama (1 < 2) {10} sivyo {20}", 10},
}
for _, tt := range tests {
evaluated := testEval(tt.input)
integer, ok := tt.expected.(int)
if ok {
testIntegerObject(t, evaluated, int64(integer))
} else {
testNullObject(t, evaluated)
}
}
}
func testNullObject(t *testing.T, obj object.Object) bool {
if obj != NULL {
t.Errorf("object is not null, got=%T(+%v)", obj, obj)
return false
}
return true
}
func TestReturnStatements(t *testing.T) {
tests := []struct {
input string
expected int64
}{
{"rudisha 10", 10},
{"rudisha 10; 9;", 10},
{"rudisha 2 * 5; 9;", 10},
{"9; rudisha 2 * 5; 9;", 10},
}
for _, tt := range tests {
evaluated := testEval(tt.input)
testIntegerObject(t, evaluated, tt.expected)
}
}
func TestErrorHandling(t *testing.T) {
tests := []struct {
input string
expectedMessage string
}{
{
"5 + kweli",
"Mstari 1: Aina Hazilingani: NAMBA + BOOLEAN",
},
{
"5 + kweli; 5;",
"Mstari 1: Aina Hazilingani: NAMBA + BOOLEAN",
},
{
"-kweli",
"Mstari 1: Operesheni Haieleweki: -BOOLEAN",
},
{
"kweli + sikweli",
"Mstari 1: Operesheni Haieleweki: BOOLEAN + BOOLEAN",
},
{
"5; kweli + sikweli; 5",
"Mstari 1: Operesheni Haieleweki: BOOLEAN + BOOLEAN",
},
{
"kama (10 > 1) { kweli + sikweli;}",
"Mstari 1: Operesheni Haieleweki: BOOLEAN + BOOLEAN",
},
{
`
kama (10 > 1) {
kama (10 > 1) {
rudisha kweli + kweli;
}
rudisha 1;
}
`,
"Mstari 4: Operesheni Haieleweki: BOOLEAN + BOOLEAN",
},
{
"bangi",
"Mstari 1: Neno Halifahamiki: bangi",
},
{
`"Habari" - "Habari"`,
"Mstari 1: Operesheni Haieleweki: NENO - NENO",
},
{
`{"jina": "Avi"}[unda(x) {x}];`,
"Mstari 1: Samahani, UNDO (FUNCTION) haitumiki kama ufunguo",
},
}
for _, tt := range tests {
evaluated := testEval(tt.input)
errObj, ok := evaluated.(*object.Error)
if !ok {
t.Errorf("no error object return, got=%T(%+v)", evaluated, evaluated)
continue
}
if errObj.Message != fmt.Sprintf(tt.expectedMessage) {
t.Errorf("wrong error message, expected=%q, got=%q", fmt.Sprintf(tt.expectedMessage), errObj.Message)
}
}
}
func TestLetStatement(t *testing.T) {
tests := []struct {
input string
expected int64
}{
{"fanya a = 5; a;", 5},
{"fanya a = 5 * 5; a;", 25},
{"fanya a = 5; fanya b = a; b;", 5},
{"fanya a = 5; fanya b = a; fanya c = a + b + 5; c;", 15},
}
for _, tt := range tests {
testIntegerObject(t, testEval(tt.input), tt.expected)
}
}
func TestFunctionObject(t *testing.T) {
input := "unda(x) { x + 2 ;};"
evaluated := testEval(input)
unda, ok := evaluated.(*object.Function)
if !ok {
t.Fatalf("object is not a Function, got=%T(%+v)", evaluated, evaluated)
}
if len(unda.Parameters) != 1 {
t.Fatalf("function has wrong parameters,Parameters=%+v", unda.Parameters)
}
if unda.Parameters[0].String() != "x" {
t.Fatalf("parameter is not x, got=%q", unda.Parameters[0])
}
expectedBody := "(x + 2)"
if unda.Body.String() != expectedBody {
t.Fatalf("body is not %q, got=%q", expectedBody, unda.Body.String())
}
}
func TestFunctionApplication(t *testing.T) {
tests := []struct {
input string
expected int64
}{
{"fanya mfano = unda(x) {x;}; mfano(5);", 5},
{"fanya mfano = unda(x) {rudisha x;}; mfano(5);", 5},
{"fanya double = unda(x) { x * 2;}; double(5);", 10},
{"fanya add = unda(x, y) {x + y;}; add(5,5);", 10},
{"fanya add = unda(x, y) {x + y;}; add(5 + 5, add(5, 5));", 20},
{"unda(x) {x;}(5)", 5},
}
for _, tt := range tests {
testIntegerObject(t, testEval(tt.input), tt.expected)
}
}
func TestClosures(t *testing.T) {
input := `
fanya newAdder = unda(x) {
unda(y) { x + y};
};
fanya addTwo = newAdder(2);
addTwo(2);
`
testIntegerObject(t, testEval(input), 4)
}
func TestStringLiteral(t *testing.T) {
input := `"Habari yako!"`
evaluated := testEval(input)
str, ok := evaluated.(*object.String)
if !ok {
t.Fatalf("Object is not string, got=%T(%+v)", evaluated, evaluated)
}
if str.Value != "Habari yako!" {
t.Errorf("String has wrong value, got=%q", str.Value)
}
}
func TestStringconcatenation(t *testing.T) {
input := `"Mambo" + " " + "Vipi" + "?"`
evaluated := testEval(input)
str, ok := evaluated.(*object.String)
if !ok {
t.Fatalf("object is not a string, got=%T(%+v)", evaluated, evaluated)
}
if str.Value != "Mambo Vipi?" {
t.Errorf("String has wrong value, got=%q", str.Value)
}
}
func TestStringMultiplyInteger(t *testing.T) {
input := `"Mambo" * 4`
evaluated := testEval(input)
str, ok := evaluated.(*object.String)
if !ok {
t.Fatalf("object is not a string, got=%T(%+v)", evaluated, evaluated)
}
if str.Value != "MamboMamboMamboMambo" {
t.Errorf("String has wrong value, got=%q", str.Value)
}
}
// func TestBuiltinFunctions(t *testing.T) {
// tests := []struct {
// input string
// expected interface{}
// }{
// {`jumla()`, "Hoja hazilingani, tunahitaji=1, tumepewa=0"},
// {`jumla("")`, "Samahani, hii function haitumiki na NENO"},
// {`jumla(1)`, "Samahani, hii function haitumiki na NAMBA"},
// {`jumla([1,2,3])`, 6},
// {`jumla([1,2,3.4])`, 6.4},
// {`jumla([1.1,2.5,3.4])`, 7},
// {`jumla([1.1,2.5,"q"])`, "Samahani namba tu zinahitajika"},
// }
// for _, tt := range tests {
// evaluated := testEval(tt.input)
// switch expected := tt.expected.(type) {
// case int:
// testIntegerObject(t, evaluated, int64(expected))
// case float64:
// testFloatObject(t, evaluated, float64(expected))
// case string:
// errObj, ok := evaluated.(*object.Error)
// if !ok {
// t.Errorf("Object is not Error, got=%T(%+v)", evaluated, evaluated)
// continue
// }
// if errObj.Message != fmt.Sprintf("\x1b[%dm%s\x1b[0m", 31, expected) {
// t.Errorf("Wrong eror message, expected=%q, got=%q", expected, errObj.Message)
// }
// }
// }
// }
func TestArrayLiterals(t *testing.T) {
input := "[1, 2 * 2, 3 + 3]"
evaluated := testEval(input)
result, ok := evaluated.(*object.Array)
if !ok {
t.Fatalf("Object is not an Array, got=%T(%+v)", evaluated, evaluated)
}
if len(result.Elements) != 3 {
t.Fatalf("Array has wrong number of elements, got=%d", len(result.Elements))
}
testIntegerObject(t, result.Elements[0], 1)
testIntegerObject(t, result.Elements[1], 4)
testIntegerObject(t, result.Elements[2], 6)
}
func TestArrayIndexExpressions(t *testing.T) {
tests := []struct {
input string
expected interface{}
}{
{
"[1, 2, 3][0]",
1,
},
{
"[1, 2, 3][1]",
2,
},
{
"[1, 2, 3][2]",
3,
},
{
"fanya i = 0; [1][i];",
1,
},
{
"fanya myArr = [1, 2, 3]; myArr[2];",
3,
},
{
"[1, 2, 3][3]",
nil,
},
{
"[1, 2, 3][-1]",
nil,
},
}
for _, tt := range tests {
evaluated := testEval(tt.input)
integer, ok := tt.expected.(int)
if ok {
testIntegerObject(t, evaluated, int64(integer))
} else {
testNullObject(t, evaluated)
}
}
}
func TestDictLiterals(t *testing.T) {
input := `fanya two = "two";
{
"one": 10 - 9,
two: 1 +1,
"thr" + "ee": 6 / 2,
4: 4,
kweli: 5,
sikweli: 6
}`
evaluated := testEval(input)
result, ok := evaluated.(*object.Dict)
if !ok {
t.Fatalf("Eval didn't return a dict, got=%T(%+v)", evaluated, evaluated)
}
expected := map[object.HashKey]int64{
(&object.String{Value: "one"}).HashKey(): 1,
(&object.String{Value: "two"}).HashKey(): 2,
(&object.String{Value: "three"}).HashKey(): 3,
(&object.Integer{Value: 4}).HashKey(): 4,
TRUE.HashKey(): 5,
FALSE.HashKey(): 6,
}
if len(result.Pairs) != len(expected) {
t.Fatalf("Dict has wrong number of pairs, got=%d", len(result.Pairs))
}
for expectedKey, expectedValue := range expected {
pair, ok := result.Pairs[expectedKey]
if !ok {
t.Errorf("No pair for give key")
}
testIntegerObject(t, pair.Value, expectedValue)
}
}
func TestDictIndexExpression(t *testing.T) {
tests := []struct {
input string
expected interface{}
}{
{
`{"foo": 5}["foo"]`,
5,
},
{
`{"foo": 5}["bar"]`,
nil,
},
{
`fanya key = "foo"; {"foo": 5}[key]`,
5,
},
{
`{}["foo"]`,
nil,
},
{
`{5: 5}[5]`,
5,
},
{
`{kweli: 5}[kweli]`,
5,
},
{
`{sikweli: 5}[sikweli]`,
5,
},
}
for _, tt := range tests {
evaluated := testEval(tt.input)
integer, ok := tt.expected.(int)
if ok {
testIntegerObject(t, evaluated, int64(integer))
} else {
testNullObject(t, evaluated)
}
}
}
func TestPrefixInteger(t *testing.T) {
tests := []struct {
input string
expected interface{}
}{
{
"-4",
-4,
},
{
"+5",
5,
},
}
for _, tt := range tests {
evaluated := testEval(tt.input)
integer, ok := tt.expected.(int)
if !ok {
t.Errorf("Object is not an integer")
}
testIntegerObject(t, evaluated, int64(integer))
}
}
func TestPrefixFloat(t *testing.T) {
tests := []struct {
input string
expected interface{}
}{
{
"-4.4",
-4.4,
},
{
"+5.5",
5.5,
},
}
for _, tt := range tests {
evaluated := testEval(tt.input)
float, ok := tt.expected.(float64)
if !ok {
t.Errorf("Object is not a float")
}
testFloatObject(t, evaluated, float)
}
}
func TestInExpression(t *testing.T) {
tests := []struct {
input string
expected bool
}{
{
"'a' ktk 'habari'",
true,
},
{
"'c' ktk 'habari'",
false,
},
{
"1 ktk [1, 2, 3]",
true,
},
{
"4 ktk [1, 2, 3]",
false,
},
{
"'a' ktk {'a': 'apple', 'b': 'banana'}",
true,
},
{
"'apple' ktk {'a': 'apple', 'b': 'banana'}",
false,
},
{
"'c' ktk {'a': 'apple', 'b': 'banana'}",
false,
},
}
for _, tt := range tests {
evaluated := testEval(tt.input)
testBooleanObject(t, evaluated, tt.expected)
}
}
func TestArrayConcatenation(t *testing.T) {
tests := []struct {
input string
expected string
}{
{
"['a', 'b', 'c'] + [1, 2, 3]",
"[a, b, c, 1, 2, 3]",
},
{
"[1, 2, 3] * 4",
"[1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3]",
},
{
"4 * [1, 2, 3]",
"[1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3]",
},
}
for _, tt := range tests {
evaluated := testEval(tt.input)
arr, ok := evaluated.(*object.Array)
if !ok {
t.Fatalf("Object is not an array, got=%T(%+v)", evaluated, evaluated)
}
if arr.Inspect() != tt.expected {
t.Errorf("Array has wrong values, got=%s want=%s", arr.Inspect(), tt.expected)
}
}
}
func TestDictConcatenation(t *testing.T) {
tests := []struct {
input string
expected map[string]string
}{
{
input: "{'a': 'apple', 'b': 'banana'} + {'c': 'cat'}",
expected: map[string]string{"a": "apple", "b": "banana", "c": "cat"},
},
{
input: "{'a':'bbb'} + {'a':'ccc'}",
expected: map[string]string{"a": "ccc"},
},
}
for _, tt := range tests {
evaluated := testEval(tt.input)
dict, ok := evaluated.(*object.Dict)
if !ok {
t.Fatalf("Object is not an dict, got=%T(%+v)", evaluated, evaluated)
}
if len(dict.Pairs) != len(tt.expected) {
t.Errorf("Dictionary has wrong number of pairs, got=%d want=%d", len(dict.Pairs), len(tt.expected))
}
}
}
func TestPostfixExpression(t *testing.T) {
inttests := []struct {
input string
expected int64
}{
{
"a=5; a++",
6,
},
{
"a=5; a--",
4,
},
}
for _, tt := range inttests {
evaluated := testEval(tt.input)
integer, ok := evaluated.(*object.Integer)
if !ok {
t.Fatalf("Object is not an integer, got=%T(%+v)", evaluated, evaluated)
}
testIntegerObject(t, integer, tt.expected)
}
floattests := []struct {
input string
expected float64
}{
{
"a=5.5; a++",
6.5,
},
{
"a=5.5; a--",
4.5,
},
}
for _, tt := range floattests {
evaluated := testEval(tt.input)
float, ok := evaluated.(*object.Float)
if !ok {
t.Fatalf("Object is not an float, got=%T(%+v)", evaluated, evaluated)
}
testFloatObject(t, float, tt.expected)
}
}
func TestWhileLoop(t *testing.T) {
input := `
i = 10
wakati (i > 0){
i--
}
i
`
evaluated := testEval(input)
i, ok := evaluated.(*object.Integer)
if !ok {
t.Fatalf("Object is not an integer, got=%T(+%v)", evaluated, evaluated)
}
if i.Value != 0 {
t.Errorf("Incorrect value, want=0 got=%d", i.Value)
}
}
func TestForLoop(t *testing.T) {
input := `
output = ""
kwa i ktk "mojo" {
output += i
}
output
`
evaluated := testEval(input)
i, ok := evaluated.(*object.String)
if !ok {
t.Fatalf("Object is not a string, got=%T(+%v)", evaluated, evaluated)
}
if i.Value != "mojo" {
t.Errorf("Wrong value: want=%s got=%s", "mojo", i.Value)
}
}
func TestBreakLoop(t *testing.T) {
input := `
i = 0
wakati (i < 10) {
kama (i == 5) {
vunja
}
i++
}
i
`
evaluated := testEval(input)
i, ok := evaluated.(*object.Integer)
if !ok {
t.Fatalf("Object is not an integer, got=%T(+%v)", evaluated, evaluated)
}
if i.Value != 5 {
t.Errorf("Wrong value: want=5, got=%d", i.Value)
}
input = `
output = ""
kwa i ktk "mojo" {
output += i
kama (i == 'o') {
vunja
}
}
output
`
evaluatedFor := testEval(input)
j, ok := evaluatedFor.(*object.String)
if !ok {
t.Fatalf("Object is not a string, got=%T", evaluated)
}
if j.Value != "mo" {
t.Errorf("Wrong value: want=%s, got=%s", "mo", j.Value)
}
}
func TestContinueLoop(t *testing.T) {
input := `
i = 0
wakati (i < 10) {
i++
kama (i == 5) {
endelea
}
i++
}
i
`
evaluated := testEval(input)
i, ok := evaluated.(*object.Integer)
if !ok {
t.Fatalf("Object is not an integer, got=%T(+%v)", evaluated, evaluated)
}
if i.Value != 11 {
t.Errorf("Wrong value: want=11, got=%d", i.Value)
}
input = `
output = ""
kwa i ktk "mojo" {
kama (i == 'o') {
endelea
}
output += i
}
output
`
evaluatedFor := testEval(input)
j, ok := evaluatedFor.(*object.String)
if !ok {
t.Fatalf("Object is not a string, got=%T", evaluated)
}
if j.Value != "mj" {
t.Errorf("Wrong value: want=%s, got=%s", "mj", j.Value)
}
}
func TestSwitchStatement(t *testing.T) {
tests := []struct {
input string
expected interface{}
}{
{
`
i = 5
badili (i) {
ikiwa 2 {
output = 2
}
ikiwa 5 {
output = 5
}
kawaida {
output = "haijulikani"
}
}
output
`,
5,
},
{
`
i = 5
badili (i) {
ikiwa 2 {
output = 2
}
kawaida {
output = "haijulikani"
}
}
output
`,
"haijulikani",
},
{
`
i = 5
badili (i) {
ikiwa 5 {
output = 5
}
ikiwa 2 {
output = 2
}
kawaida {
output = "haijulikani"
}
}
output
`,
5,
},
}
for _, tt := range tests {
evaluated := testEval(tt.input)
switch expected := tt.expected.(type) {
case int:
testIntegerObject(t, evaluated, int64(expected))
case string:
s, ok := evaluated.(*object.String)
if !ok {
t.Fatalf("Object is not a string, got=%T", evaluated)
}
if s.Value != tt.expected {
t.Errorf("Wrong Value, want='haijulikani', got=%s", s.Value)
}
}
}
}
func TestAssignEqual(t *testing.T) {
tests := []struct {
input string
expected interface{}
}{
{"a = 5; a += 5",
10,
},
{
"a = 5; a -= 5",
0,
},
{
"a = 5; a *= 10",
50,
},
{
"a = 100; a /= 4",
25,
},
{
`
a = [1, 2, 3]
a[0] += 500
a[0]
`,
501,
},
{
`
a = "mambo"
a += " vipi"
`,
"mambo vipi",
},
{
"a = 5.5; a += 4.5",
10.0,
},
{
"a = 11.3; a -= 0.8",
10.5,
},
{
"a = 0.4; a /= 2",
0.2,
},
{
"a = 0.1; a *= 10",
1.0,
},
}
for _, tt := range tests {
evaluated := testEval(tt.input)
switch expected := tt.expected.(type) {
case int:
testIntegerObject(t, evaluated, int64(expected))
case float64:
testFloatObject(t, evaluated, float64(expected))
case string:
s, ok := evaluated.(*object.String)
if !ok {
t.Fatalf("Object not a string, got=%T", evaluated)
}
if s.Value != tt.expected {
t.Errorf("Wrong value, want=%s, got=%s", tt.expected, s.Value)
}
}
}
}
func TestStringMethods(t *testing.T) {
tests := []struct {
input string
expected interface{}
}{
{
"'mambo'.idadi()",
5,
},
{
"'mambo'.herufikubwa()",
"MAMBO",
},
{
"'MaMbO'.herufindogo()",
"mambo",
},
{
"'habari'.gawa('a')",
"[h, b, ri]",
},
}
for _, tt := range tests {
evaluated := testEval(tt.input)
switch expected := tt.expected.(type) {
case int:
testIntegerObject(t, evaluated, int64(expected))
case string:
switch eval := evaluated.(type) {
case *object.String:
s, ok := evaluated.(*object.String)
if !ok {
t.Fatalf("Object not of type string, got=%T", eval)
}
if s.Value != tt.expected {
t.Errorf("Wrong value: want=%s, got=%s", tt.expected, s.Value)
}
case *object.Array:
arr, ok := evaluated.(*object.Array)
if !ok {
t.Fatalf("Object not of type array, got=%T", eval)
}
if arr.Inspect() != tt.expected {
t.Errorf("Wrong value: want=%s, got=%s", tt.expected, arr.Inspect())
}
}
}
}
}
func TestTimeModule(t *testing.T) {
input := `
tumia muda
muda.hasahivi()
`
evaluated := testEval(input)
muda, ok := evaluated.(*object.Time)
if !ok {
t.Fatalf("Object is not a time object, got=%T", evaluated)
}
_, err := time.Parse("15:04:05 02-01-2006", muda.TimeValue)
if err != nil {
t.Errorf("Wrong time value: got=%v", err)
}
}
================================================
FILE: evaluator/forin.go
================================================
package evaluator
import (
"github.com/NuruProgramming/Nuru/ast"
"github.com/NuruProgramming/Nuru/object"
)
func evalForInExpression(fie *ast.ForIn, env *object.Environment, line int) object.Object {
iterable := Eval(fie.Iterable, env)
existingKeyIdentifier, okk := env.Get(fie.Key) // again, stay safe
existingValueIdentifier, okv := env.Get(fie.Value)
defer func() { // restore them later on
if okk {
env.Set(fie.Key, existingKeyIdentifier)
}
if okv {
env.Set(fie.Value, existingValueIdentifier)
}
}()
switch i := iterable.(type) {
case object.Iterable:
defer func() {
i.Reset()
}()
return loopIterable(i.Next, env, fie)
default:
return newError("Mstari %d: Huwezi kufanya operesheni hii na %s", line, i.Type())
}
}
================================================
FILE: evaluator/function.go
================================================
package evaluator
import (
"github.com/NuruProgramming/Nuru/ast"
"github.com/NuruProgramming/Nuru/object"
)
func evalFunction(node *ast.FunctionLiteral, env *object.Environment) object.Object {
function := &object.Function{
Name: node.Name,
Parameters: node.Parameters,
Defaults: node.Defaults,
Body: node.Body,
Env: env,
}
return function
}
================================================
FILE: evaluator/identifier.go
================================================
package evaluator
import (
"github.com/NuruProgramming/Nuru/ast"
"github.com/NuruProgramming/Nuru/object"
)
func evalIdentifier(node *ast.Identifier, env *object.Environment) object.Object {
if val, ok := env.Get(node.Value); ok {
return val
}
if builtin, ok := builtins[node.Value]; ok {
return builtin
}
return newError("Mstari %d: Neno Halifahamiki: %s", node.Token.Line, node.Value)
}
================================================
FILE: evaluator/if.go
================================================
package evaluator
import (
"github.com/NuruProgramming/Nuru/ast"
"github.com/NuruProgramming/Nuru/object"
)
func evalIfExpression(ie *ast.IfExpression, env *object.Environment) object.Object {
condition := Eval(ie.Condition, env)
if isError(condition) {
return condition
}
if isTruthy(condition) {
return Eval(ie.Consequence, env)
} else if ie.Alternative != nil {
return Eval(ie.Alternative, env)
} else {
return NULL
}
}
================================================
FILE: evaluator/import.go
================================================
package evaluator
import (
"fmt"
"os"
"path/filepath"
"strings"
"github.com/NuruProgramming/Nuru/ast"
"github.com/NuruProgramming/Nuru/lexer"
"github.com/NuruProgramming/Nuru/module"
"github.com/NuruProgramming/Nuru/object"
"github.com/NuruProgramming/Nuru/parser"
)
var searchPaths []string
func evalImport(node *ast.Import, env *object.Environment) object.Object {
for k, v := range node.Identifiers {
if mod, ok := module.Mapper[v.Value]; ok {
env.Set(k, mod)
} else {
return evalImportFile(k, v, env)
}
}
return NULL
}
func evalImportFile(name string, ident *ast.Identifier, env *object.Environment) object.Object {
addSearchPath("")
filename := findFile(name)
if filename == "" {
return newError("Moduli %s haipo", name)
}
var scope *object.Environment
scope, err := evaluateFile(filename, env)
if err != nil {
return err
}
return importFile(name, ident, env, scope)
}
func addSearchPath(path string) {
searchPaths = append(searchPaths, path)
}
func findFile(name string) string {
basename := fmt.Sprintf("%s.nr", name)
for _, path := range searchPaths {
file := filepath.Join(path, basename)
if fileExists(file) {
return file
}
}
return ""
}
func fileExists(file string) bool {
_, err := os.Stat(file)
return err == nil
}
func evaluateFile(file string, env *object.Environment) (*object.Environment, object.Object) {
source, err := os.ReadFile(file)
if err != nil {
return nil, &object.Error{Message: fmt.Sprintf("Tumeshindwa kufungua pakeji: %s", file)}
}
l := lexer.New(string(source))
p := parser.New(l)
program := p.ParseProgram()
if len(p.Errors()) != 0 {
return nil, &object.Error{Message: fmt.Sprintf("Pakeji %s ina makosa yafuatayo:\n%s", file, strings.Join(p.Errors(), "\n"))}
}
scope := object.NewEnvironment()
result := Eval(program, scope)
if isError(result) {
return nil, result
}
return scope, nil
}
func importFile(name string, ident *ast.Identifier, env *object.Environment, scope *object.Environment) object.Object {
value, ok := scope.Get(ident.Value)
if !ok {
return newError("%s sio pakeji", name)
}
env.Set(name, value)
return NULL
}
================================================
FILE: evaluator/in.go
================================================
package evaluator
import (
"strings"
"github.com/NuruProgramming/Nuru/object"
)
func evalInExpression(left, right object.Object, line int) object.Object {
switch right.(type) {
case *object.String:
return evalInStringExpression(left, right)
case *object.Array:
return evalInArrayExpression(left, right)
case *object.Dict:
return evalInDictExpression(left, right, line)
default:
return FALSE
}
}
func evalInStringExpression(left, right object.Object) object.Object {
if left.Type() != object.STRING_OBJ {
return FALSE
}
leftVal := left.(*object.String)
rightVal := right.(*object.String)
found := strings.Contains(rightVal.Value, leftVal.Value)
return nativeBoolToBooleanObject(found)
}
func evalInDictExpression(left, right object.Object, line int) object.Object {
leftVal, ok := left.(object.Hashable)
if !ok {
return newError("Mstari %d: Huwezi kutumia kama 'key': %s", line, left.Type())
}
key := leftVal.HashKey()
rightVal := right.(*object.Dict).Pairs
_, ok = rightVal[key]
return nativeBoolToBooleanObject(ok)
}
func evalInArrayExpression(left, right object.Object) object.Object {
rightVal := right.(*object.Array)
switch leftVal := left.(type) {
case *object.Null:
for _, v := range rightVal.Elements {
if v.Type() == object.NULL_OBJ {
return TRUE
}
}
case *object.String:
for _, v := range rightVal.Elements {
if v.Type() == object.STRING_OBJ {
elem := v.(*object.String)
if elem.Value == leftVal.Value {
return TRUE
}
}
}
case *object.Integer:
for _, v := range rightVal.Elements {
if v.Type() == object.INTEGER_OBJ {
elem := v.(*object.Integer)
if elem.Value == leftVal.Value {
return TRUE
}
}
}
case *object.Float:
for _, v := range rightVal.Elements {
if v.Type() == object.FLOAT_OBJ {
elem := v.(*object.Float)
if elem.Value == leftVal.Value {
return TRUE
}
}
}
}
return FALSE
}
================================================
FILE: evaluator/index.go
================================================
package evaluator
import "github.com/NuruProgramming/Nuru/object"
func evalIndexExpression(left, index object.Object, line int) object.Object {
switch {
case left.Type() == object.ARRAY_OBJ && index.Type() == object.INTEGER_OBJ:
return evalArrayIndexExpression(left, index)
case left.Type() == object.ARRAY_OBJ && index.Type() != object.INTEGER_OBJ:
return newError("Mstari %d: Tafadhali tumia number, sio: %s", line, index.Type())
case left.Type() == object.DICT_OBJ:
return evalDictIndexExpression(left, index, line)
default:
return newError("Mstari %d: Operesheni hii haiwezekani kwa: %s", line, left.Type())
}
}
func evalArrayIndexExpression(array, index object.Object) object.Object {
arrayObject := array.(*object.Array)
idx := index.(*object.Integer).Value
max := int64(len(arrayObject.Elements) - 1)
if idx < 0 || idx > max {
return NULL
}
return arrayObject.Elements[idx]
}
func evalDictIndexExpression(dict, index object.Object, line int) object.Object {
dictObject := dict.(*object.Dict)
key, ok := index.(object.Hashable)
if !ok {
return newError("Mstari %d: Samahani, %s haitumiki kama ufunguo", line, index.Type())
}
pair, ok := dictObject.Pairs[key.HashKey()]
if !ok {
return NULL
}
return pair.Value
}
================================================
FILE: evaluator/infix.go
================================================
package evaluator
import (
"math"
"strings"
"github.com/NuruProgramming/Nuru/object"
)
func evalInfixExpression(operator string, left, right object.Object, line int) object.Object {
if right == nil {
return newError("Mstari %d: Umekosea hapa", line)
}
if left == nil {
return newError("Mstari %d: Umekosea hapa", line)
}
switch {
case operator == "ktk":
return evalInExpression(left, right, line)
case left.Type() == object.STRING_OBJ && right.Type() == object.STRING_OBJ:
return evalStringInfixExpression(operator, left, right, line)
case operator == "+" && left.Type() == object.DICT_OBJ && right.Type() == object.DICT_OBJ:
leftVal := left.(*object.Dict).Pairs
rightVal := right.(*object.Dict).Pairs
pairs := make(map[object.HashKey]object.DictPair)
for k, v := range leftVal {
pairs[k] = v
}
for k, v := range rightVal {
pairs[k] = v
}
return &object.Dict{Pairs: pairs}
case operator == "+" && left.Type() == object.ARRAY_OBJ && right.Type() == object.ARRAY_OBJ:
leftVal := left.(*object.Array).Elements
rightVal := right.(*object.Array).Elements
elements := append(leftVal, rightVal...)
return &object.Array{Elements: elements}
case operator == "*" && left.Type() == object.ARRAY_OBJ && right.Type() == object.INTEGER_OBJ:
leftVal := left.(*object.Array).Elements
rightVal := int(right.(*object.Integer).Value)
elements := leftVal
for i := rightVal; i > 1; i-- {
elements = append(elements, leftVal...)
}
return &object.Array{Elements: elements}
case operator == "*" && left.Type() == object.INTEGER_OBJ && right.Type() == object.ARRAY_OBJ:
leftVal := int(left.(*object.Integer).Value)
rightVal := right.(*object.Array).Elements
elements := rightVal
for i := leftVal; i > 1; i-- {
elements = append(elements, rightVal...)
}
return &object.Array{Elements: elements}
case operator == "*" && left.Type() == object.STRING_OBJ && right.Type() == object.INTEGER_OBJ:
leftVal := left.(*object.String).Value
rightVal := right.(*object.Integer).Value
return &object.String{Value: strings.Repeat(leftVal, int(rightVal))}
case operator == "*" && left.Type() == object.INTEGER_OBJ && right.Type() == object.STRING_OBJ:
leftVal := left.(*object.Integer).Value
rightVal := right.(*object.String).Value
return &object.String{Value: strings.Repeat(rightVal, int(leftVal))}
case left.Type() == object.INTEGER_OBJ && right.Type() == object.INTEGER_OBJ:
return evalIntegerInfixExpression(operator, left, right, line)
case left.Type() == object.FLOAT_OBJ && right.Type() == object.FLOAT_OBJ:
return evalFloatInfixExpression(operator, left, right, line)
case left.Type() == object.INTEGER_OBJ && right.Type() == object.FLOAT_OBJ:
return evalFloatIntegerInfixExpression(operator, left, right, line)
case left.Type() == object.FLOAT_OBJ && right.Type() == object.INTEGER_OBJ:
return evalFloatIntegerInfixExpression(operator, left, right, line)
case operator == "==":
return nativeBoolToBooleanObject(left == right)
case operator == "!=":
return nativeBoolToBooleanObject(left != right)
case left.Type() == object.BOOLEAN_OBJ && right.Type() == object.BOOLEAN_OBJ:
return evalBooleanInfixExpression(operator, left, right, line)
case left.Type() != right.Type():
return newError("Mstari %d: Aina Hazilingani: %s %s %s",
line, left.Type(), operator, right.Type())
default:
return newError("Mstari %d: Operesheni Haieleweki: %s %s %s",
line, left.Type(), operator, right.Type())
}
}
func evalFloatIntegerInfixExpression(operator string, left, right object.Object, line int) object.Object {
var leftVal, rightVal float64
if left.Type() == object.FLOAT_OBJ {
leftVal = left.(*object.Float).Value
rightVal = float64(right.(*object.Integer).Value)
} else {
leftVal = float64(left.(*object.Integer).Value)
rightVal = right.(*object.Float).Value
}
var val float64
switch operator {
case "+":
val = leftVal + rightVal
case "-":
val = leftVal - rightVal
case "*":
val = leftVal * rightVal
case "**":
val = math.Pow(float64(leftVal), float64(rightVal))
case "/":
val = leftVal / rightVal
case "%":
val = math.Mod(leftVal, rightVal)
case "<":
return nativeBoolToBooleanObject(leftVal < rightVal)
case "<=":
return nativeBoolToBooleanObject(leftVal <= rightVal)
case ">":
return nativeBoolToBooleanObject(leftVal > rightVal)
case ">=":
return nativeBoolToBooleanObject(leftVal >= rightVal)
case "==":
return nativeBoolToBooleanObject(leftVal == rightVal)
case "!=":
return nativeBoolToBooleanObject(leftVal != rightVal)
default:
return newError("Mstari %d: Operesheni Haieleweki: %s %s %s",
line, left.Type(), operator, right.Type())
}
if math.Mod(val, 1) == 0 {
return &object.Integer{Value: int64(val)}
} else {
return &object.Float{Value: val}
}
}
func evalStringInfixExpression(operator string, left, right object.Object, line int) object.Object {
leftVal := left.(*object.String).Value
rightVal := right.(*object.String).Value
switch operator {
case "+":
return &object.String{Value: leftVal + rightVal}
case "==":
return nativeBoolToBooleanObject(leftVal == rightVal)
case "!=":
return nativeBoolToBooleanObject(leftVal != rightVal)
default:
return newError("Mstari %d: Operesheni Haieleweki: %s %s %s", line, left.Type(), operator, right.Type())
}
}
func evalBooleanInfixExpression(operator string, left, right object.Object, line int) object.Object {
leftVal := left.(*object.Boolean).Value
rightVal := right.(*object.Boolean).Value
switch operator {
case "&&":
return nativeBoolToBooleanObject(leftVal && rightVal)
case "||":
return nativeBoolToBooleanObject(leftVal || rightVal)
default:
return newError("Mstari %d: Operesheni Haieleweki: %s %s %s", line, left.Type(), operator, right.Type())
}
}
func evalFloatInfixExpression(operator string, left, right object.Object, line int) object.Object {
leftVal := left.(*object.Float).Value
rightVal := right.(*object.Float).Value
switch operator {
case "+":
return &object.Float{Value: leftVal + rightVal}
case "-":
return &object.Float{Value: leftVal - rightVal}
case "*":
return &object.Float{Value: leftVal * rightVal}
case "**":
return &object.Float{Value: math.Pow(float64(leftVal), float64(rightVal))}
case "/":
return &object.Float{Value: leftVal / rightVal}
case "<":
return nativeBoolToBooleanObject(leftVal < rightVal)
case "<=":
return nativeBoolToBooleanObject(leftVal <= rightVal)
case ">":
return nativeBoolToBooleanObject(leftVal > rightVal)
case ">=":
return nativeBoolToBooleanObject(leftVal >= rightVal)
case "==":
return nativeBoolToBooleanObject(leftVal == rightVal)
case "!=":
return nativeBoolToBooleanObject(leftVal != rightVal)
default:
return newError("Mstari %d: Operesheni Haieleweki: %s %s %s",
line, left.Type(), operator, right.Type())
}
}
func evalIntegerInfixExpression(operator string, left, right object.Object, line int) object.Object {
leftVal := left.(*object.Integer).Value
rightVal := right.(*object.Integer).Value
switch operator {
case "+":
return &object.Integer{Value: leftVal + rightVal}
case "-":
return &object.Integer{Value: leftVal - rightVal}
case "*":
return &object.Integer{Value: leftVal * rightVal}
case "**":
return &object.Float{Value: float64(math.Pow(float64(leftVal), float64(rightVal)))}
case "/":
x := float64(leftVal) / float64(rightVal)
if math.Mod(x, 1) == 0 {
return &object.Integer{Value: int64(x)}
} else {
return &object.Float{Value: x}
}
case "%":
return &object.Integer{Value: leftVal % rightVal}
case "<":
return nativeBoolToBooleanObject(leftVal < rightVal)
case "<=":
return nativeBoolToBooleanObject(leftVal <= rightVal)
case ">":
return nativeBoolToBooleanObject(leftVal > rightVal)
case ">=":
return nativeBoolToBooleanObject(leftVal >= rightVal)
case "==":
return nativeBoolToBooleanObject(leftVal == rightVal)
case "!=":
return nativeBoolToBooleanObject(leftVal != rightVal)
default:
return newError("Mstari %d: Operesheni Haieleweki: %s %s %s",
line, left.Type(), operator, right.Type())
}
}
================================================
FILE: evaluator/method.go
================================================
package evaluator
import (
"github.com/NuruProgramming/Nuru/ast"
"github.com/NuruProgramming/Nuru/object"
)
func evalMethodExpression(node *ast.MethodExpression, env *object.Environment) object.Object {
obj := Eval(node.Object, env)
if isError(obj) {
return obj
}
args := evalExpressions(node.Arguments, env)
if len(args) == 1 && isError(args[0]) {
return args[0]
}
defs := make(map[string]object.Object)
for k, v := range node.Defaults {
defs[k] = Eval(v, env)
}
return applyMethod(obj, node.Method, args, defs, node.Token.Line)
}
func applyMethod(obj object.Object, method ast.Expression, args []object.Object, defs map[string]object.Object, l int) object.Object {
switch obj := obj.(type) {
case *object.String:
return obj.Method(method.(*ast.Identifier).Value, args)
case *object.File:
return obj.Method(method.(*ast.Identifier).Value, args)
case *object.Time:
return obj.Method(method.(*ast.Identifier).Value, args, defs)
case *object.Array:
switch method.(*ast.Identifier).Value {
case "map":
return maap(obj, args)
case "chuja":
return filter(obj, args)
default:
return obj.Method(method.(*ast.Identifier).Value, args)
}
case *object.Module:
if fn, ok := obj.Functions[method.(*ast.Identifier).Value]; ok {
return fn(args, defs)
}
case *object.Instance:
if fn, ok := obj.Package.Scope.Get(method.(*ast.Identifier).Value); ok {
fn.(*object.Function).Env.Set("@", obj)
ret := applyFunction(fn, args, l)
fn.(*object.Function).Env.Del("@")
return ret
}
case *object.Package:
if fn, ok := obj.Scope.Get(method.(*ast.Identifier).Value); ok {
fn.(*object.Function).Env.Set("@", obj)
ret := applyFunction(fn, args, l)
fn.(*object.Function).Env.Del("@")
return ret
}
}
return newError("Samahani, %s haina function '%s()'", obj.Inspect(), method.(*ast.Identifier).Value)
}
// ///////////////////////////////////////////////////////////////
// //////// Some methods here because of loop dependency ////////
// /////////////////////////////////////////////////////////////
func maap(a *object.Array, args []object.Object) object.Object {
if len(args) != 1 && args[0].Type() != object.FUNCTION_OBJ {
return newError("Samahani, hoja sii sahihi")
}
fn, ok := args[0].(*object.Function)
if !ok {
return newError("Samahani, hoja sii sahihi")
}
env := object.NewEnvironment()
newArr := object.Array{Elements: []object.Object{}}
for _, obj := range a.Elements {
env.Set(fn.Parameters[0].Value, obj)
r := Eval(fn.Body, env)
if o, ok := r.(*object.ReturnValue); ok {
r = o.Value
}
newArr.Elements = append(newArr.Elements, r)
}
return &newArr
}
func filter(a *object.Array, args []object.Object) object.Object {
if len(args) != 1 && args[0].Type() != object.FUNCTION_OBJ {
return newError("Samahani, hoja sii sahihi")
}
fn, ok := args[0].(*object.Function)
if !ok {
return newError("Samahani, hoja sii sahihi")
}
env := object.NewEnvironment()
newArr := object.Array{Elements: []object.Object{}}
for _, obj := range a.Elements {
env.Set(fn.Parameters[0].Value, obj)
cond := Eval(fn.Body, env)
if cond.Inspect() == "kweli" {
newArr.Elements = append(newArr.Elements, obj)
}
}
return &newArr
}
================================================
FILE: evaluator/package.go
================================================
package evaluator
import (
"github.com/NuruProgramming/Nuru/ast"
"github.com/NuruProgramming/Nuru/object"
)
func evalPackage(node *ast.Package, env *object.Environment) object.Object {
pakeji := &object.Package{
Name: node.Name,
Env: env,
Scope: object.NewEnclosedEnvironment(env),
}
Eval(node.Block, pakeji.Scope)
env.Set(node.Name.Value, pakeji)
return pakeji
}
================================================
FILE: evaluator/postfix.go
================================================
package evaluator
import (
"github.com/NuruProgramming/Nuru/ast"
"github.com/NuruProgramming/Nuru/object"
)
func evalPostfixExpression(env *object.Environment, operator string, node *ast.PostfixExpression) object.Object {
val, ok := env.Get(node.Token.Literal)
if !ok {
return newError("Tumia KITAMBULISHI CHA NAMBA AU DESIMALI, sio %s", node.Token.Type)
}
switch operator {
case "++":
switch arg := val.(type) {
case *object.Integer:
v := arg.Value + 1
return env.Set(node.Token.Literal, &object.Integer{Value: v})
case *object.Float:
v := arg.Value + 1
return env.Set(node.Token.Literal, &object.Float{Value: v})
default:
return 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)
}
case "--":
switch arg := val.(type) {
case *object.Integer:
v := arg.Value - 1
return env.Set(node.Token.Literal, &object.Integer{Value: v})
case *object.Float:
v := arg.Value - 1
return env.Set(node.Token.Literal, &object.Float{Value: v})
default:
return 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)
}
default:
return newError("Haifahamiki: %s", operator)
}
}
================================================
FILE: evaluator/prefix.go
================================================
package evaluator
import "github.com/NuruProgramming/Nuru/object"
func evalMinusPrefixOperatorExpression(right object.Object, line int) object.Object {
switch obj := right.(type) {
case *object.Integer:
return &object.Integer{Value: -obj.Value}
case *object.Float:
return &object.Float{Value: -obj.Value}
default:
return newError("Mstari %d: Operesheni Haieleweki: -%s", line, right.Type())
}
}
func evalPlusPrefixOperatorExpression(right object.Object, line int) object.Object {
switch obj := right.(type) {
case *object.Integer:
return &object.Integer{Value: obj.Value}
case *object.Float:
return &object.Float{Value: obj.Value}
default:
return newError("Mstari %d: Operesheni Haieleweki: +%s", line, right.Type())
}
}
func evalPrefixExpression(operator string, right object.Object, line int) object.Object {
switch operator {
case "!":
return evalBangOperatorExpression(right)
case "-":
return evalMinusPrefixOperatorExpression(right, line)
case "+":
return evalPlusPrefixOperatorExpression(right, line)
default:
return newError("Mstari %d: Operesheni Haieleweki: %s%s", line, operator, right.Type())
}
}
================================================
FILE: evaluator/property.go
================================================
package evaluator
import (
"github.com/NuruProgramming/Nuru/ast"
"github.com/NuruProgramming/Nuru/object"
)
func evalPropertyExpression(node *ast.PropertyExpression, env *object.Environment) object.Object {
left := Eval(node.Object, env)
if isError(left) {
return left
}
switch left.(type) {
case *object.Instance:
obj := left.(*object.Instance)
prop := node.Property.(*ast.Identifier).Value
if val, ok := obj.Env.Get(prop); ok {
return val
}
case *object.Package:
obj := left.(*object.Package)
prop := node.Property.(*ast.Identifier).Value
if val, ok := obj.Env.Get(prop); ok {
return val
}
// case *object.Module:
// mod := left.(*object.Module)
// prop := node.Property.(*ast.Identifier).Value
// if val, ok := mod.Properties[prop]; ok {
// return val()
// }
}
return newError("Value %s sii sahihi kwenye %s", node.Property.(*ast.Identifier).Value, left.Inspect())
}
func evalPropertyAssignment(name *ast.PropertyExpression, val object.Object, env *object.Environment) object.Object {
left := Eval(name.Object, env)
if isError(left) {
return left
}
switch left.(type) {
case *object.Instance:
obj := left.(*object.Instance)
prop := name.Property.(*ast.Identifier).Value
if _, ok := obj.Env.Get(prop); ok {
obj.Env.Set(prop, val)
return NULL
}
obj.Env.Set(prop, val)
return NULL
case *object.Package:
obj := left.(*object.Package)
prop := name.Property.(*ast.Identifier).Value
if _, ok := obj.Env.Get(prop); ok {
obj.Env.Set(prop, val)
return NULL
}
obj.Env.Set(prop, val)
return NULL
default:
return newError("Imeshindikana kuweka kwenye pakiti %s", left.Type())
}
}
================================================
FILE: evaluator/switch.go
================================================
package evaluator
import (
"github.com/NuruProgramming/Nuru/ast"
"github.com/NuruProgramming/Nuru/object"
)
func evalSwitchStatement(se *ast.SwitchExpression, env *object.Environment) object.Object {
obj := Eval(se.Value, env)
for _, opt := range se.Choices {
if opt.Default {
continue
}
for _, val := range opt.Expr {
out := Eval(val, env)
if obj.Type() == out.Type() && obj.Inspect() == out.Inspect() {
blockOut := evalBlockStatement(opt.Block, env)
return blockOut
}
}
}
for _, opt := range se.Choices {
if opt.Default {
out := evalBlockStatement(opt.Block, env)
return out
}
}
return nil
}
================================================
FILE: evaluator/type.go
================================================
package evaluator
import (
"strconv"
"github.com/NuruProgramming/Nuru/object"
)
func convertToInteger(obj object.Object) object.Object {
switch obj := obj.(type) {
case *object.Integer:
return obj
case *object.Float:
return &object.Integer{Value: int64(obj.Value)}
case *object.String:
i, err := strconv.ParseInt(obj.Value, 10, 64)
if err != nil {
return newError("Haiwezi kubadilisha '%s' kuwa NAMBA", obj.Value)
}
return &object.Integer{Value: i}
case *object.Boolean:
if obj.Value {
return &object.Integer{Value: 1}
}
return &object.Integer{Value: 0}
default:
return newError("Haiwezi kubadilisha %s kuwa NAMBA", obj.Type())
}
}
func convertToFloat(obj object.Object) object.Object {
switch obj := obj.(type) {
case *object.Float:
return obj
case *object.Integer:
return &object.Float{Value: float64(obj.Value)}
case *object.String:
f, err := strconv.ParseFloat(obj.Value, 64)
if err != nil {
return newError("Haiwezi kubadilisha '%s' kuwa DESIMALI", obj.Value)
}
return &object.Float{Value: f}
case *object.Boolean:
if obj.Value {
return &object.Float{Value: 1.0}
}
return &object.Float{Value: 0.0}
default:
return newError("Haiwezi kubadilisha %s kuwa DESIMALI", obj.Type())
}
}
func convertToString(obj object.Object) object.Object {
return &object.String{Value: obj.Inspect()}
}
func convertToBoolean(obj object.Object) object.Object {
switch obj := obj.(type) {
case *object.Boolean:
return obj
case *object.Integer:
return &object.Boolean{Value: obj.Value != 0}
case *object.Float:
return &object.Boolean{Value: obj.Value != 0}
case *object.String:
return &object.Boolean{Value: len(obj.Value) > 0}
case *object.Null:
return &object.Boolean{Value: false}
default:
return &object.Boolean{Value: true}
}
}
================================================
FILE: evaluator/while.go
================================================
package evaluator
import (
"github.com/NuruProgramming/Nuru/ast"
"github.com/NuruProgramming/Nuru/object"
)
const MAX_ITERATIONS = 1_000_000
func evalWhileExpression(we *ast.WhileExpression, env *object.Environment) object.Object {
var evaluated object.Object
iterations := 0
for {
iterations++
if iterations > MAX_ITERATIONS {
return newError("mzunguko usio na mwisho umegunduliwa")
}
condition := Eval(we.Condition, env)
if isError(condition) {
return condition
}
if !isTruthy(condition) {
break
}
evaluated = Eval(we.Consequence, env)
if isError(evaluated) {
return evaluated
}
if evaluated != nil && evaluated.Type() == object.BREAK_OBJ {
return evaluated
}
}
return evaluated
}
================================================
FILE: examples/Astart.nr
================================================
/*############ A*(A-star) Algorithm ##############
By @VictorKariuki
https://github.com/VictorKariuki
################################################*/
// create a list of numbers
fanya list = unda(first,last,interval){
fanya list = [first];
fanya i = first + interval;
wakati(i < last){
list.sukuma(i)
i+=interval;
}
rudisha list;
}
// Maths functions
// find the absolute value of a number
fanya abs_namba = unda(namba){
kama(namba < 0){
rudisha -1 * namba;
}
rudisha namba;
}
// square a number
fanya square = unda(n, i, j){
fanya kati = (i+j)/2;
fanya mul = kati * kati;
fanya abs_diff = abs_namba(mul-n);
kama (mul == n || abs_diff < 0.00001){
rudisha kati;
}au kama(mul < n){
rudisha square(n,kati,j)
}au{
rudisha square(n,i,kati)
}
}
// find the square root of a number
fanya sqrt = unda(namba){
kwa i ktk list(0,namba,1) {
kama((i*i )== namba){
rudisha i;
}au kama ((i*i )> namba){
rudisha square(namba,i-1,i)
}
}
}
// Main function
fanya aStar = unda(start, goal) {
// Initialize the open and closed lists
fanya openList = [start];
fanya closedList = [];
fanya reconstructPath = unda(node) {
fanya path = [node];
wakati (node["parent"]) {
path = [node["parent"]] + path;
node = node["parent"];
}
rudisha path;
}
fanya heuristic = unda(node1, node2) {
// Calculate the Euclidean distance between the nodes' positions
fanya dx = node1["x"] - node2["x"];
fanya dy = node1["y"] - node2["y"];
rudisha sqrt(dx * dx + dy * dy);
}
fanya findMinNode = unda(openList) {
fanya i = 1;
fanya minNode = openList[0];
wakati (i < openList.idadi()) {
fanya node = openList[i];
kama (node["f"] < minNode["f"]) {
minNode = node;
}
i++
}
rudisha minNode;
}
fanya removeNodeFromArray = unda(array, node) {
fanya newArray = [];
fanya i = 1;
wakati (i < array.idadi()) {
kama (array[i] != node) {
newArray.sukuma(array[i]);
}
i++;
}
rudisha newArray;
}
fanya urefu = unda(node1, node2) {
// Assume all edges have a cost of 1
rudisha 1;
}
// Initialize the g and f scores of the starting node
start["g"] = 0;
start["f"] = start["g"] + heuristic(start, goal);
// Start the search loop
wakati (openList.idadi() > 0) {
// Find the node with the lowest f score in the open list
fanya current = findMinNode(openList);
// Check kama the goal node has been reached
kama (current == goal) {
rudisha reconstructPath(current);
}
// Move the current node from the open to the closed list
openList = removeNodeFromArray(openList, current);
closedList.sukuma(current);
// Explore the neighbors of the current node
kwa neighbor ktk current["neighbors"] {
// Skip neighbors that are in the closed list
kama (neighbor ktk closedList) {
endelea
}
// Calculate the tentative g score of the neighbor
fanya tentativeG = start["g"] + urefu(current, neighbor);
// Check kama the neighbor is in the open list
fanya tentativeIsBetter = sikweli;
kama (!(neighbor ktk openList)) {
openList.sukuma(neighbor);
tentativeIsBetter = kweli;
} au kama (tentativeG < neighbor["g"]) {
tentativeIsBetter = kweli;
}
// Update the neighbor's g score kama the tentative score is better
kama (tentativeIsBetter) {
neighbor["g"] = tentativeG;
neighbor["f"] = neighbor["g"] + heuristic(neighbor, goal);
neighbor["parent"] = current;
}
}
}
// kama the open list is empty, no path was found
rudisha tupu;
}
// Define the nodes of the graph
fanya nodeA = { "x": 0, "y": 0, "neighbors": [] };
fanya nodeB = { "x": 1, "y": 2, "neighbors": [] };
fanya nodeC = { "x": 3, "y": 1, "neighbors": [] };
fanya nodeD = { "x": 4, "y": 3, "neighbors": [] };
// Define the edges between the nodes
nodeA["neighbors"] = [nodeB];
nodeB["neighbors"] = [nodeA, nodeC];
nodeC["neighbors"] = [nodeB, nodeD];
nodeD["neighbors"] = [nodeC];
// Call the A* function with the start and goal nodes and the heuristic and distance functions
//fanya path = aStar(nodeA, nodeC);
andika(nodeA);
================================================
FILE: examples/example.nr
================================================
// basics
jina = "Nuru"
andika(jina) // Nuru
// lists
orodha = [1, "pili", kweli]
namba = [10, 20, 30]
jina = namba[1] // jina is 20
namba[1] = 25
a = [1, 2, 3]
b = [4, 5, 6]
c = a + b // c is now [1, 2, 3, 4, 5, 6]
namba = [10, 20, 30]
andika(20 ktk namba) // will print kweli
namba = [1, 2, 3, 4, 5]
kwa thamani ktk namba {
andika(thamani)
}
majina = ["Juma", "Asha", "Haruna"]
kwa idx, jina ktk majina {
andika(idx, "-", jina)
}
a = [1, 2, 3]
urefu = a.idadi()
andika(urefu) // will print 3
a = [1, 2, 3]
a.sukuma("s", "g")
andika(a) // will print [1, 2, 3, "s", "g"]
a = [1, 2, 3]
mwisho = a.yamwisho()
andika(mwisho) // will print 3
b = []
mwisho = b.yamwisho()
andika(mwisho) // will print tupu
andika(1 > 2) // Output: `sikweli`
andika(1 + 3 < 10) // Output: `kweli`
a = 5
b = 10
c = 15
result = (a < b) && (b < c)
kama (result) {
andika("Both conditions are true")
} sivyo {
andika("At least one condition is false")
}
// Output: "Both conditions are true"
andika(kweli && kweli) // Output: `kweli`
andika(kweli && sikweli) // Output: `sikweli`
andika(kweli || sikweli) // Output: `kweli`
andika(sikweli || sikweli) // Output: `sikweli`
andika(!kweli) // Output: `sikweli`
andika(!sikweli) // Output: `kweli`
namba = [1, 2, 3, 4, 5]
kwa thamani ktk namba {
kama (thamani % 2 == 0) {
andika(thamani, "is even")
} sivyo {
andika(thamani, "is odd")
}
}
// Output:
// 1 is odd
// 2 is even
// 3 is odd
// 4 is even
// 5 is odd
salamu = unda() {
jina = jaza("Unaitwa nani? ")
andika("Mambo vipi", jina)
}
salamu()
aina(2) // Output: "NAMBA"
aina("Nuru") // Output: "NENO"
orodha = {"jina": "Juma", "umri": 25}
k = {
"jina": "Juma",
"umri": 25,
kweli: "kweli",
"salimu": unda(x) { andika("habari", x) },
"sina value": tupu
}
andika(k[kweli]) // kweli
andika(k["salimu"]("Juma")) // habari Juma
k['umri'] = 30
andika(k['umri']) // 30
k["lugha"] = "Kiswahili"
andika(k["lugha"]) // Kiswahili
matunda = {"a": "apple", "b": "banana"}
mboga = {"c": "carrot", "d": "daikon"}
vyakula = matunda + mboga
andika(vyakula) // {"a": "apple", "b": "banana", "c": "carrot", "d": "daikon"}
"umri" ktk k // kweli
"urefu" ktk k // sikweli
hobby = {"a": "asili", "b": "baiskeli", "c": "chakula"}
kwa i, v ktk hobby {
andika(i, "=>", v)
}
/* a => asili
b => baiskeli
c => chakula */
kwa v ktk hobby {
andika(v)
}
/*
asili
baiskeli
chakula
*/
jina = "lugano"
kwa i ktk jina {
andika(i)
}
kamusi = {"a": "andaa", "b": "baba"}
kwa v ktk kamusi {
andika(v)
}
kwa k, v ktk kamusi {
andika(k + " ni " + v)
}
kwa v ktk "mojo" {
andika(v)
}
kwa i, v ktk "mojo" {
andika(i, "->", v)
}
majina = ["juma", "asha", "haruna"]
kwa v ktk majina {
andika(v)
}
kwa i, v ktk majina {
andika(i, "-", v)
}
kwa i, v ktk "mojo" {
kama (i == 2) {
andika("nimevunja")
vunja
}
andika(v)
}
kwa i, v ktk "mojo" {
kama (i == 2) {
andika("nimeruka")
endelea
}
andika(v)
}
jum = unda(x, y) {
rudisha x + y
}
jum(2, 3) // 5
salamu = unda() {
andika("Habari yako")
}
salamu()
salamu = unda(jina) {
andika("Habari yako", jina)
}
salamu("asha") // Habari yako asha
salimu = unda(salamu="Habari") {
andika(salamu)
}
salimu() // Habari
salimu("Mambo") // Mambo
mfano = unda(x) {
rudisha "nimerudi"
andika(x)
}
mfano("x") // nimerudi
fib = unda(n) {
kama (n <= 1) {
rudisha n
} sivyo {
rudisha fib(n-1) + fib(n-2)
}
}
andika(fib(10)) // 55
jum = unda(x) {
rudisha unda(y) {
rudisha x + y
}
}
jum_x = jum(5)
andika(jum_x(3)) // 8
2 + 3 * 5 // 17
a = 2.5
b = 3/5
a + b // 2.8
i = 2.4
i++ // 3.4
i = 2
i *= 3 // 6
i /= 2 // 3
i += 100 // 103
i -= 10 // 93
i %= 90 // 3
i = -10
wakati (i < 0) {
andika(i)
i++
}
andika("mambo") // mambo
a = 'niaje'
andika("mambo", a) // mambo niaje
a = "habari" + " " + "yako"
andika(a) // habari yako
b = "habari"
b += " yako"
// habari yako
andika("mambo " * 4)
// mambo mambo mambo mambo
a = "habari"
a *= 4
// habarihabarihabarihabari
jina = "avicenna"
kwa i ktk jina {andika(i)}
a = "nuru"
andika(a == "nuru") // kweli
andika(a == "mambo") // sikweli
a = "mambo"
a.idadi() // 5
a = "NURU"
a.herufindogo() // nuru
a = "nuru mambo habari"
b = a.gawa()
andika(b) // ["nuru", "mambo", "habari"]
a = "nuru,mambo,habari"
b = a.gawa(",")
andika(b) // ["nuru", "mambo", "habari"]
a = 2
badili (a){
ikiwa 3 {
andika("a ni tatu")
}
ikiwa 2 {
andika ("a ni mbili")
}
}
badili (a) {
ikiwa 1,2,3 {
andika("a ni kati ya 1, 2 au 3")
}
ikiwa 4 {
andika("a ni 4")
}
}
z = 20
badili(z) {
ikiwa 10 {
andika("kumi")
}
ikiwa 30 {
andika("thelathini")
}
kawaida {
andika("ishirini")
}
}
i = 1
wakati (i <= 5) {
andika(i)
i++
}
i = 1
wakati (i < 5) {
kama (i == 3) {
andika("nimevunja")
vunja
}
andika(i)
i++
}
i = 0
wakati (i < 5) {
i++
kama (i == 3) {
andika("nimeruka")
endelea
}
andika(i)
}
// using time:
tumia muda
andika(muda.hasahivi())
andika("Tunalala")
muda.lala(2)
andika("Tumeamka")
s = muda.hasahivi()
muda.lala(2)
andika(muda.tangu(s))
andika(s.ongeza(sekunde=3, miaka=10, dakika=4))
// using file:
fail = fungua("sarufi.nr")
andika(fail.soma())
// using net and json:
tumia mtandao, jsoni
url = "https://v2.jokeapi.dev/joke/Any?type=single"
resp = mtandao.peruzi(url)
resp = jsoni.dikodi(resp)
andika(resp["joke"])
// os module
tumia os
andika(os.kimbiza("pwd"))
os.toka(0)
================================================
FILE: examples/perceptron.nr
================================================
tumia hisabati
// Mbinu za Kupanga
//orodhesha(kwanza, mwisho, umbali), huunda orodha ya nambari na umbali uliowekwa kati yao.
fanya orodhesha = unda(kwanza, mwisho, umbali){
fanya orodha = [kwanza];
fanya i = kwanza + umbali;
wakati(i < mwisho){
orodha.sukuma(i);
i += umbali;
}
rudisha orodha;
}
// Kuanzisha uzani bila mpangilio
fanya mizani = [
hisabati.random() * 2 - 1,
hisabati.random() * 2 - 1,
hisabati.random() * 2 - 1
];
// Undo la uanzishaji wa Sigmoid
fanya sigmoid = unda(vekta) {
fanya tokeo = [];
kwa v ktk vekta {
tokeo.sukuma(1 / (1 + hisabati.exp(-1 * v)));
}
rudisha tokeo;
}
// Derivative ya undo la sigmoid
fanya sigmoidDerivative = unda(vekta) {
andika("vekta: ",vekta)
fanya tokeo = [];
kwa v ktk vekta {
tokeo.sukuma(v * (1 - v));
}
rudisha tokeo;
}
fanya kuzidishaMatrikiVekta = unda(matriki, vekta) {
fanya tokeo = [];
kwa row ktk matriki {
fanya jamii = 0;
kwa j, kipengee ktk row {
jamii += kipengee * vekta[j];
}
tokeo.sukuma(jamii);
}
rudisha tokeo;
}
fanya zidishaKwaNukta = unda(safu1, safu2) {
// Angalia ikiwa safu zina urefu sawa
kama (safu1.idadi() != safu2.idadi()) {
andika("Safu lazima ziwe na urefu sawa kwa kuzidisha kwa busara ya kipengele.");
}
// Perform element-wise multiplication
fanya tokeo = [];
kwa i, kipengee ktk safu1 {
tokeo.sukuma(kipengee * safu2[i]);
}
rudisha tokeo;
}
// Songa mbele kupitia mtandao wa neva
fanya waza = unda(pembejeo, mizani) {
fanya jumlaYaUzani = sigmoid(kuzidishaMatrikiVekta(pembejeo, mizani));
rudisha jumlaYaUzani;
}
fanya badiliMatriki = unda(matrix) {
// Pata idadi ya safu mlalo na safu wima katika matrix asili
fanya nambari_ya_safu_mlalo = matrix.idadi();
fanya nambari_ya_safu_wima = matrix[0].idadi();
// Unda matrix mpya na safu mlalo na safu wima zilizobadilishwa
fanya matrikiIliyobadili = [];
// Pita ndani ya safu wima
kwa safu_wima_ya, safuW ktk orodhesha(0, nambari_ya_safu_wima, 1){
// Anzisha safu mlalo mpya kwa matriki iliyopitishwa
fanya transposed_safu_mlalo = [];
// Pita ndani ya safu mlalo
kwa safu_mlalo_ya, safu ktk orodhesha(0, nambari_ya_safu_mlalo, 1){
// Sukuma kipengele kwenye safu wima ya sasa na safu mlalo hadi safu iliyopitishwa
transposed_safu_mlalo.sukuma(matrix[safu_mlalo_ya][safu_wima_ya]);
}
// Sukuma safu mlalo iliyopitishwa kwenye matriki lililopitishwa
matrikiIliyobadili.sukuma(transposed_safu_mlalo);
}
rudisha matrikiIliyobadili;
}
// Funza mtandao wa neva
fanya funza = unda(mizani, mafunzoPembejeo, matokeoYaMafunzo, marudioYaMafunzo) {
fanya kurudia = 0
andika('\nmafunzoPembejeo: ');
andika(mafunzoPembejeo);
andika('\nmatokeoYaMafunzo: ');
andika(matokeoYaMafunzo);
fanya orodha = orodhesha(0, marudioYaMafunzo, 1)
// andika("orodha: ",orodha)
kwa i ktk orodha{
andika('\n\nkurudia: ');
andika(i);
// Pitisha mafunzo yaliyowekwa kupitia mtandao wa neva
fanya pato = waza(mafunzoPembejeo, mizani);
andika('\npato: ');
andika(pato);
// Kuhesabu kiwango cha upungufu
fanya upungufu = [];
kwa i, kipengee ktk matokeoYaMafunzo {
upungufu.sukuma(kipengee - pato[i]);
}
andika('\nupungufu: ');
andika(upungufu);
fanya sigmoidDerivative_ya_pato = sigmoidDerivative(pato)
andika('\nsigmoidDerivative tokeo: ');
andika(sigmoidDerivative_ya_pato);
fanya zidishaKwaNukta_tokeo = zidishaKwaNukta(upungufu, sigmoidDerivative_ya_pato);
andika('\nzidishaKwaNukta tokeo: ');
andika(zidishaKwaNukta_tokeo);
fanya mafunzoPembejeoYaliyobadili = badiliMatriki(mafunzoPembejeo)
andika('\nmafunzo pembejeo yaliyobadili: ');
andika(mafunzoPembejeoYaliyobadili);
// Kuzidisha upungufu kwa pembejeo na upinde rangi ya kitendakazi cha sigmoid
// Uzito mdogo wa ujasiri hurekebishwa zaidi kupitia asili ya kazi
fanya marekebisho = kuzidishaMatrikiVekta(mafunzoPembejeo, zidishaKwaNukta_tokeo);
andika('\nmarekebisho tokeo: ');
andika(marekebisho);
// Rekebisha uzani
kwa i, j ktk mizani {
mizani[i] = mizani[i] + marekebisho[i];
}
andika('\nmizani mpya: ');
andika(mizani);
kurudia++
}
rudisha mizani;
}
andika('\nMizani ya Kuanzisha isiyo na mpangilio: ');
andika(mizani);
// Seti ya mafunzo
fanya mafunzoPembejeo = [[0, 0, 1], [1, 1, 1], [1, 0, 1], [0, 1, 1]];
fanya matokeoYaMafunzo = [0, 1, 1, 0];
// Funza mtandao wa neva
fanya mafunzoMizani = funza(mizani, mafunzoPembejeo, matokeoYaMafunzo, 10000);
andika('\nMizani baada ya mafunzo:');
andika(mafunzoMizani);
// Ingizo la mtumiaji kwa hali mpya
fanya A = 0;
fanya B = 0;
fanya C = 1;
andika('\nHali mpya: data ya pembejeo = ', A, B, C);
andika('\nData ya pato:');
andika(waza([[A, B, C]], mafunzoMizani));
================================================
FILE: examples/reduce.nr
================================================
fanya reduce = unda(iterator, callback, initialValue) {
fanya accumulator = initialValue;
kwa thamani ktk iterator {
accumulator = callback(accumulator, thamani);
}
rudisha accumulator;
}
fanya list = [1,2,3,4,5];
fanya employees = [{"salary":120},{"salary":135},{"salary":140}]
fanya sum = unda(acc,value){
rudisha acc + value;
}
fanya mul = unda(acc,value){
rudisha acc * value;
}
fanya sumSalo = unda(acc,value){
rudisha acc + value["salary"];
}
fanya sumSaloWithTax = unda(acc,value){
rudisha acc + (value["salary"] * (1-0.34));
}
andika(reduce(list,sum,0))
andika(reduce(list,mul,1))
andika(reduce(employees,sumSalo,0))
andika(reduce(employees,sumSaloWithTax,0))
================================================
FILE: examples/sarufi.nr
================================================
tumia mtandao
tumia jsoni
pakeji sarufi {
andaa = unda(file) {
config = fungua(file)
configString = config.soma()
configDict = jsoni.dikodi(configString)
clientID = configDict["client_id"]
clientSecret = configDict["client_secret"]
params = {"client_id": clientID, "client_secret": clientSecret}
tokenString = mtandao.tuma(yuareli="https://api.sarufi.io/api/access_token", mwili=params)
tokenDict = jsoni.dikodi(tokenString)
@.token = tokenDict["access_token"]
@.Auth = "Bearer " + @.token
}
tokenYangu = unda() {
rudisha @.token
}
tengenezaChatbot = unda(data) {
majibu = mtandao.tuma(yuareli="https://api.sarufi.io/chatbot", vichwa={"Authorization": @.Auth}, mwili = data)
rudisha majibu
}
pataChatbotZote = unda() {
majibu = mtandao.peruzi(yuareli="https://api.sarufi.io/chatbots", vichwa={"Authorization": @.Auth})
rudisha majibu
}
}
================================================
FILE: examples/sorting_algorithm.nr
================================================
/*
############ Sorting Algorithm ##############
By @VictorKariuki
https://github.com/VictorKariuki
#############################################
*/
slice = unda(arr,start, end) {
result = []
wakati (start < end) {
result = result + [arr[start]]
start = start + 1
}
rudisha result
}
merge = unda(left, right) {
result = []
lLen = left.idadi()
rLen = right.idadi()
l = 0
r = 0
wakati (l < lLen && r < rLen) {
kama (left[l] < right[r]) {
result = result + [left[l]]
l = l + 1
} sivyo {
result = result + [right[r]]
r = r + 1
}
}
andika(result)
}
mergeSort = unda(arr){
len = arr.idadi()
andika("arr is ", arr," of length ", len)
kama (len < 2) {
rudisha arr
}
andika("len is greater than or == to 2", len > 1)
mid = (len / 2)
andika("arr has a mid point of ", mid)
left = slice(arr, 0, mid)
right = slice(arr, mid, len)
andika("left slice is ", left)
andika("right slice is ", right)
sortedLeft = mergeSort(left)
sortedRight = mergeSort(right)
andika("sortedLeft is ", sortedLeft)
andika("sortedRight is ", sortedRight)
rudisha merge(sortedLeft, sortedRight)
}
arr = [6, 5, 3, 1, 8, 7, 2, 4]
sortedArray = mergeSort(arr)
andika(sortedArray)
================================================
FILE: examples/sudoku_solver.nr
================================================
/*########### Backtracking Algorithm ##############
By @VictorKariuki
https://github.com/VictorKariuki
NURU program to solve Sudoku using Backtracking Algorithm
The sudoku puzzle is represented as a 2D array. The empty
cells are represented by 0. The algorithm works by trying
out all possible numbers for an empty cell. If the number
is valid, it is placed in the cell. If the number is invalid,
the algorithm backtracks to the previous cell and tries
another number. The algorithm terminates when all cells
are filled. The algorithm is implemented in the solveSudoku
function. The isValid function checks kama a number is
valid in a given cell. The printSudoku function prints
the sudoku puzzle. The solveSudoku function solves the
sudoku puzzle. The main function initializes the sudoku
puzzle and calls the solveSudoku function.
#################################################*/
fanya printing = unda(sudoku) {
fanya row = 0
wakati (row < 9){
andika(sudoku[row])
row++
}
}
fanya 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]]
fanya isSafe = unda(grid, row, col, num) {
kwa x ktk [0,1,2,3,4,5,6,7,8] {
kama (grid[row][x] == num) {
rudisha sikweli
}
}
kwa x ktk [0,1,2,3,4,5,6,7,8] {
kama (grid[x][col] == num) {
rudisha sikweli
}
}
fanya startRow = row - row % 3
fanya startCol = col - col % 3
kwa i ktk [0, 1, 2] {
kwa j ktk [0, 1, 2] {
kama (grid[i + startRow][j + startCol] == num) {
rudisha sikweli
}
}
}
rudisha kweli
}
fanya solveSudoku = unda(grid, row, col) {
kama (row == 8 && col == 9) {
rudisha kweli
}
kama (col == 9) {
row += 1
col = 0
}
kama (grid[row][col] > 0) {
rudisha solveSudoku(grid, row, col + 1)
}
kwa num ktk [1,2,3,4,5,6,7,8,9] {
kama (isSafe(grid, row, col, num)) {
grid[row][col] = num
kama (solveSudoku(grid, row, col + 1)) {
rudisha kweli
}
}
grid[row][col] = 0
}
rudisha sikweli
}
andika()
andika("----- PUZZLE TO SOLVE -----")
printing(sudoku)
kama (solveSudoku(sudoku, 0, 0)){
andika()
andika("--------- SOLUTION --------")
printing(sudoku)
andika()
} sivyo {
andika("imeshindikana")
}
================================================
FILE: extensions/README.md
================================================
# Nuru Extensions For Various Editors
## [VSCODE](./vscode/)
Nuru syntax highlighting on VSCode
## [VIM](./vim)
The file contained herein has a basic syntax highlight for vim.
The file should be saved in `$HOME/.vim/syntax/nuru.vim`.
You should add the following line to your `.vimrc` or the appropriate location:
```vim
au BufRead,BufNewFile *.nr set filetype=nuru
```
Only basic syntax highlighting is provided by the script.
================================================
FILE: extensions/vim/syntax/nuru.vim
================================================
" Sintaksia ya nuru kwenye programu ya "vim"
" Lugha: Nuru
" Maneno tengwa
syntax keyword nuruKeyword unda pakeji rudisha vunja endelea tupu
syntax keyword nuruType fanya
syntax keyword nuruBool kweli sikweli
syntax keyword nuruConditional kama sivyo au
syntax match nuruComparision /[!\|<>]/
syntax keyword nuruLoop ktk while badili
syntax keyword nuruLabel ikiwa kawaida
" Nambari
syntax match nuruInt '[+-]\d\+' contained display
syntax match nuruFloat '[+-]\d+\.\d*' contained display
" Viendeshaji
syntax match nuruAssignment '='
syntax match nuruLogicalOP /[\&!|]/
" Vitendakazi
syntax keyword nuruFunction andika aina jaza fungua
" Tungo
syntax region nuruString start=/"/ skip=/\\"/ end=/"/
syntax region nuruString start=/'/ skip=/\\'/ end=/'/
" Maoni
syntax match nuruComment "//.*"
syntax region nuruComment start="/\*" end="\*/"
" Fafanua sintaksia
let b:current_syntax = "nuru"
highlight def link nuruComment Comment
highlight def link nuruBool Boolean
highlight def link nuruFunction Function
highlight def link nuruComparision Conditional
highlight def link nuruConditional Conditional
highlight def link nuruKeyword Keyword
highlight def link nuruString String
highlight def link nuruVariable Identifier
highlight def link nuruLoop Repeat
highlight def link nuruInt Number
highlight def link nuruFloat Float
highlight def link nuruAssignment Operator
highlight def link nuruLogicalOP Operator
highlight def link nuruAriOP Operator
highlight def link nuruType Type
highlight def link nuruLabel Label
================================================
FILE: extensions/vscode/CHANGELOG.md
================================================
# Change Log
All notable changes to the "nuru" extension will be documented in this file.
Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how to structure this file.
## [Unreleased]
- Initial release
================================================
FILE: extensions/vscode/README.md
================================================
# Nuru VSCode Extension
This is a syntax highliting extension for Nuru on vscode. It detects `.nr` and `.sw` files.
## Screenshots
<p align="center">
<img alt="Nuru Programming Language" src="assets/screenshot.png">
</p>
## How To Install
### Download From Market Place
- Simply download the Nuru Extension from VSCode Market Place
### Windows
- 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`
- Restart VSCode
### Linux and MacOS
- 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`
- Restart VSCode
================================================
FILE: go.mod
================================================
module github.com/NuruProgramming/Nuru
go 1.18
require (
github.com/AvicennaJr/GoPrompt v0.0.0-20230411215003-be2316d88e2d
github.com/charmbracelet/bubbles v0.15.0
github.com/charmbracelet/bubbletea v0.23.2
github.com/charmbracelet/glamour v0.6.0
github.com/charmbracelet/lipgloss v0.7.1
github.com/lrstanley/bubblezone v0.0.0-20230303230241-08f906ff62a9
)
require (
github.com/alecthomas/chroma v0.10.0 // indirect
github.com/atotto/clipboard v0.1.4 // indirect
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
github.com/aymerick/douceur v0.2.0 // indirect
github.com/containerd/console v1.0.3 // indirect
github.com/dlclark/regexp2 v1.4.0 // indirect
github.com/gorilla/css v1.0.0 // indirect
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
github.com/mattn/go-colorable v0.1.7 // indirect
github.com/mattn/go-isatty v0.0.18 // indirect
github.com/mattn/go-localereader v0.0.1 // indirect
github.com/mattn/go-runewidth v0.0.14 // indirect
github.com/mattn/go-tty v0.0.3 // indirect
github.com/microcosm-cc/bluemonday v1.0.21 // indirect
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect
github.com/muesli/cancelreader v0.2.2 // indirect
github.com/muesli/reflow v0.3.0 // indirect
github.com/muesli/termenv v0.15.1 // indirect
github.com/olekukonko/tablewriter v0.0.5 // indirect
github.com/pkg/term v1.2.0-beta.2 // indirect
github.com/rivo/uniseg v0.4.4 // indirect
github.com/sahilm/fuzzy v0.1.0 // indirect
github.com/yuin/goldmark v1.5.2 // indirect
github.com/yuin/goldmark-emoji v1.0.1 // indirect
golang.org/x/net v0.0.0-20221002022538-bcab6841153b // indirect
golang.org/x/sync v0.1.0 // indirect
golang.org/x/sys v0.7.0 // indirect
golang.org/x/term v0.7.0 // indirect
golang.org/x/text v0.9.0 // indirect
)
================================================
FILE: go.sum
================================================
github.com/AvicennaJr/GoPrompt v0.0.0-20230411215003-be2316d88e2d h1:H+Y1MQQXd83x0xC2MPOw+gFFozKTXgcW69bV80+/wpY=
github.com/AvicennaJr/GoPrompt v0.0.0-20230411215003-be2316d88e2d/go.mod h1:oo6I+tik505nlWIPCU2ogWMkOxoTt7A1YwQYlmlHqE8=
github.com/alecthomas/chroma v0.10.0 h1:7XDcGkCQopCNKjZHfYrNLraA+M7e0fMiJ/Mfikbfjek=
github.com/alecthomas/chroma v0.10.0/go.mod h1:jtJATyUxlIORhUOFNA9NZDWGAQ8wpxQQqNSB4rjA/1s=
github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4=
github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI=
github.com/aymanbagabas/go-osc52 v1.0.3/go.mod h1:zT8H+Rk4VSabYN90pWyugflM3ZhpTZNC7cASDfUCdT4=
github.com/aymanbagabas/go-osc52 v1.2.1/go.mod h1:zT8H+Rk4VSabYN90pWyugflM3ZhpTZNC7cASDfUCdT4=
github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk=
github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4=
github.com/charmbracelet/bubbles v0.15.0 h1:c5vZ3woHV5W2b8YZI1q7v4ZNQaPetfHuoHzx+56Z6TI=
github.com/charmbracelet/bubbles v0.15.0/go.mod h1:Y7gSFbBzlMpUDR/XM9MhZI374Q+1p1kluf1uLl8iK74=
github.com/charmbracelet/bubbletea v0.23.1/go.mod h1:JAfGK/3/pPKHTnAS8JIE2u9f61BjWTQY57RbT25aMXU=
github.com/charmbracelet/bubbletea v0.23.2 h1:vuUJ9HJ7b/COy4I30e8xDVQ+VRDUEFykIjryPfgsdps=
github.com/charmbracelet/bubbletea v0.23.2/go.mod h1:FaP3WUivcTM0xOKNmhciz60M6I+weYLF76mr1JyI7sM=
github.com/charmbracelet/glamour v0.6.0 h1:wi8fse3Y7nfcabbbDuwolqTqMQPMnVPeZhDM273bISc=
github.com/charmbracelet/glamour v0.6.0/go.mod h1:taqWV4swIMMbWALc0m7AfE9JkPSU8om2538k9ITBxOc=
github.com/charmbracelet/harmonica v0.2.0/go.mod h1:KSri/1RMQOZLbw7AHqgcBycp8pgJnQMYYT8QZRqZ1Ao=
github.com/charmbracelet/lipgloss v0.6.0/go.mod h1:tHh2wr34xcHjC2HCXIlGSG1jaDF0S0atAUvBMP6Ppuk=
github.com/charmbracelet/lipgloss v0.7.1 h1:17WMwi7N1b1rVWOjMT+rCh7sQkvDU75B2hbZpc5Kc1E=
github.com/charmbracelet/lipgloss v0.7.1/go.mod h1:yG0k3giv8Qj8edTCbbg6AlQ5e8KNWpFujkNawKNhE2c=
github.com/containerd/console v1.0.3 h1:lIr7SlA5PxZyMV30bDW0MGbiOPXwc63yRuCP0ARubLw=
github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dlclark/regexp2 v1.4.0 h1:F1rxgk7p4uKjwIQxBs9oAXe5CqrXlCduYEJvrF4u93E=
github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
github.com/gorilla/css v1.0.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY=
github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c=
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/lrstanley/bubblezone v0.0.0-20230303230241-08f906ff62a9 h1:w7W7F0EBRNTRRy+MFNLGrhJLn2Ldzl8Ms2AtHtgFtuw=
github.com/lrstanley/bubblezone v0.0.0-20230303230241-08f906ff62a9/go.mod h1:v5lEwWaguF1o2MW/ucO0ZIA/IZymdBYJJ+2cMRLE7LU=
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-colorable v0.1.7 h1:bQGKb3vps/j0E9GfJQ03JyhRuxsvdAanXlT9BTw3mdw=
github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.18 h1:DOKFKCQ7FNG2L1rbrmstDN4QVRdS89Nkh85u68Uwp98=
github.com/mattn/go-isatty v0.0.18/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4=
github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88=
github.com/mattn/go-runewidth v0.0.6/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mattn/go-runewidth v0.0.10/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU=
github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mattn/go-tty v0.0.3 h1:5OfyWorkyO7xP52Mq7tB36ajHDG5OHrmBGIS/DtakQI=
github.com/mattn/go-tty v0.0.3/go.mod h1:ihxohKRERHTVzN+aSVRwACLCeqIoZAWpoICkkvrWyR0=
github.com/microcosm-cc/bluemonday v1.0.21 h1:dNH3e4PSyE4vNX+KlRGHT5KrSvjeUkoNPwEORjffHJg=
github.com/microcosm-cc/bluemonday v1.0.21/go.mod h1:ytNkv4RrDrLJ2pqlsSI46O6IVXmZOBBD4SaJyDwwTkM=
github.com/muesli/ansi v0.0.0-20211018074035-2e021307bc4b/go.mod h1:fQuZ0gauxyBcmsdE3ZT4NasjaRdxmbCS0jRHsrWu3Ho=
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI=
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6/go.mod h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo=
github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA=
github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo=
github.com/muesli/reflow v0.2.1-0.20210115123740-9e1d0d53df68/go.mod h1:Xk+z4oIWdQqJzsxyjgl3P22oYZnHdZ8FFTHAQQt5BMQ=
github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s=
github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8=
github.com/muesli/termenv v0.11.1-0.20220204035834-5ac8409525e0/go.mod h1:Bd5NYQ7pd+SrtBSrSNoBBmXlcY8+Xj4BMJgh8qcZrvs=
github.com/muesli/termenv v0.13.0/go.mod h1:sP1+uffeLaEYpyOTb8pLCUctGcGLnoFjSn4YJK5e2bc=
github.com/muesli/termenv v0.14.0/go.mod h1:kG/pF1E7fh949Xhe156crRUrHNyK221IuGO7Ez60Uc8=
github.com/muesli/termenv v0.15.1 h1:UzuTb/+hhlBugQz28rpzey4ZuKcZ03MeKsoG7IJZIxs=
github.com/muesli/termenv v0.15.1/go.mod h1:HeAQPTzpfs016yGtA4g00CsdYnVLJvxsS4ANqrZs2sQ=
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
github.com/pkg/term v1.2.0-beta.2 h1:L3y/h2jkuBVFdWiJvNfYfKmzcCnILw7mJWm2JQuMppw=
github.com/pkg/term v1.2.0-beta.2/go.mod h1:E25nymQcrSllhX42Ok8MRm1+hyBdHY0dCeiKZ9jpNGw=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis=
github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/sahilm/fuzzy v0.1.0 h1:FzWGaw2Opqyu+794ZQ9SYifWv2EIXpwP4q8dY1kDAwI=
github.com/sahilm/fuzzy v0.1.0/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.5.2 h1:ALmeCk/px5FSm1MAcFBAsVKZjDuMVj8Tm7FFIlMJnqU=
github.com/yuin/goldmark v1.5.2/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/yuin/goldmark-emoji v1.0.1 h1:ctuWEyzGBwiucEqxzwe0SOYDXPAucOrE9NQC18Wa1os=
github.com/yuin/goldmark-emoji v1.0.1/go.mod h1:2w1E6FEWLcDQkoTE+7HU6QF1F6SLlNGjRIBbIZQFqkQ=
golang.org/x/net v0.0.0-20221002022538-bcab6841153b h1:6e93nYa3hNqAvLr0pD4PN1fFS+gKzp2zAXqrnTCstqU=
golang.org/x/net v0.0.0-20221002022538-bcab6841153b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220204135822-1c1b9b1eba6a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU=
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.7.0 h1:BEvjmm5fURWqcfbSKTdpkDXYBrUS1c0m8agp14W48vQ=
golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
================================================
FILE: lexer/lexer.go
================================================
// This will convert the sequence of characters into a sequence of tokens
package lexer
import (
"github.com/NuruProgramming/Nuru/token"
)
type Lexer struct {
input []rune
position int
readPosition int
ch rune
line int
}
func New(input string) *Lexer {
l := &Lexer{input: []rune(input), line: 1}
l.readChar()
return l
}
func (l *Lexer) readChar() {
if l.readPosition >= len(l.input) {
l.ch = 0
} else {
l.ch = l.input[l.readPosition]
}
l.position = l.readPosition
l.readPosition += 1
}
func (l *Lexer) NextToken() token.Token {
var tok token.Token
l.skipWhitespace()
if l.ch == rune('/') && l.peekChar() == rune('/') {
l.skipSingleLineComment()
return l.NextToken()
}
if l.ch == rune('/') && l.peekChar() == rune('*') {
l.skipMultiLineComment()
return l.NextToken()
}
switch l.ch {
case rune('='):
if l.peekChar() == rune('=') {
ch := l.ch
l.readChar()
tok = token.Token{Type: token.EQ, Literal: string(ch) + string(l.ch), Line: l.line}
} else {
tok = newToken(token.ASSIGN, l.line, l.ch)
}
case rune(';'):
tok = newToken(token.SEMICOLON, l.line, l.ch)
case rune('('):
tok = newToken(token.LPAREN, l.line, l.ch)
case rune(')'):
tok = newToken(token.RPAREN, l.line, l.ch)
case rune('{'):
tok = newToken(token.LBRACE, l.line, l.ch)
case rune('}'):
tok = newToken(token.RBRACE, l.line, l.ch)
case rune(','):
tok = newToken(token.COMMA, l.line, l.ch)
case rune('+'):
if l.peekChar() == rune('=') {
ch := l.ch
l.readChar()
tok = token.Token{Type: token.PLUS_ASSIGN, Line: l.line, Literal: string(ch) + string(l.ch)}
} else if l.peekChar() == rune('+') {
ch := l.ch
l.readChar()
tok = token.Token{Type: token.PLUS_PLUS, Literal: string(ch) + string(l.ch), Line: l.line}
} else {
tok = newToken(token.PLUS, l.line, l.ch)
}
case rune('-'):
if l.peekChar() == rune('=') {
ch := l.ch
l.readChar()
tok = token.Token{Type: token.MINUS_ASSIGN, Line: l.line, Literal: string(ch) + string(l.ch)}
} else if l.peekChar() == rune('-') {
ch := l.ch
l.readChar()
tok = token.Token{Type: token.MINUS_MINUS, Literal: string(ch) + string(l.ch), Line: l.line}
} else {
tok = newToken(token.MINUS, l.line, l.ch)
}
case rune('!'):
if l.peekChar() == rune('=') {
ch := l.ch
l.readChar()
tok = token.Token{Type: token.NOT_EQ, Literal: string(ch) + string(l.ch), Line: l.line}
} else {
tok = newToken(token.BANG, l.line, l.ch)
}
case rune('/'):
if l.peekChar() == rune('=') {
ch := l.ch
l.readChar()
tok = token.Token{Type: token.SLASH_ASSIGN, Line: l.line, Literal: string(ch) + string(l.ch)}
} else {
tok = newToken(token.SLASH, l.line, l.ch)
}
case rune('*'):
if l.peekChar() == rune('=') {
ch := l.ch
l.readChar()
tok = token.Token{Type: token.ASTERISK_ASSIGN, Line: l.line, Literal: string(ch) + string(l.ch)}
} else if l.peekChar() == rune('*') {
ch := l.ch
l.readChar()
tok = token.Token{Type: token.POW, Literal: string(ch) + string(l.ch), Line: l.line}
} else {
tok = newToken(token.ASTERISK, l.line, l.ch)
}
case rune('<'):
if l.peekChar() == rune('=') {
ch := l.ch
l.readChar()
tok = token.Token{Type: token.LTE, Literal: string(ch) + string(l.ch), Line: l.line}
} else {
tok = newToken(token.LT, l.line, l.ch)
}
case rune('>'):
if l.peekChar() == rune('=') {
ch := l.ch
l.readChar()
tok = token.Token{Type: token.GTE, Literal: string(ch) + string(l.ch), Line: l.line}
} else {
tok = newToken(token.GT, l.line, l.ch)
}
case rune('"'):
tok.Type = token.STRING
tok.Literal = l.readString()
tok.Line = l.line
case rune('\''):
tok = token.Token{Type: token.STRING, Literal: l.readSingleQuoteString(), Line: l.line}
case rune('['):
tok = newToken(token.LBRACKET, l.line, l.ch)
case rune(']'):
tok = newToken(token.RBRACKET, l.line, l.ch)
case rune(':'):
tok = newToken(token.COLON, l.line, l.ch)
case rune('@'):
tok = newToken(token.AT, l.line, l.ch)
case rune('.'):
tok = newToken(token.DOT, l.line, l.ch)
case rune('&'):
if l.peekChar() == rune('&') {
ch := l.ch
l.readChar()
tok = token.Token{Type: token.AND, Literal: string(ch) + string(l.ch), Line: l.line}
}
case rune('|'):
if l.peekChar() == rune('|') {
ch := l.ch
l.readChar()
tok = token.Token{Type: token.OR, Literal: string(ch) + string(l.ch), Line: l.line}
}
case rune('%'):
if l.peekChar() == rune('=') {
ch := l.ch
l.readChar()
tok = token.Token{Type: token.MODULUS_ASSIGN, Line: l.line, Literal: string(ch) + string(l.ch)}
} else {
tok = newToken(token.MODULUS, l.line, l.ch)
}
case rune('#'):
if l.peekChar() == rune('!') && l.line == 1 {
l.skipSingleLineComment()
return l.NextToken()
}
case 0:
tok.Literal = ""
tok.Type = token.EOF
tok.Line = l.line
default:
if isLetter(l.ch) {
tok.Literal = l.readIdentifier()
tok.Type = token.LookupIdent(tok.Literal)
tok.Line = l.line
return tok
} else if isDigit(l.ch) && isLetter(l.peekChar()) {
tok.Literal = l.readIdentifier()
tok.Type = token.LookupIdent(tok.Literal)
tok.Line = l.line
return tok
} else if isDigit(l.ch) {
tok = l.readDecimal()
return tok
} else {
tok = newToken(token.ILLEGAL, l.line, l.ch)
}
}
l.readChar()
return tok
}
func newToken(tokenType token.TokenType, line int, ch rune) token.Token {
return token.Token{Type: tokenType, Literal: string(ch), Line: line}
}
func (l *Lexer) readIdentifier() string {
position := l.position
for isLetter(l.ch) || isDigit(l.ch) {
l.readChar()
}
return string(l.input[position:l.position])
}
func isLetter(ch rune) bool {
return 'a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z' || ch == '_' || ch == '@'
}
func (l *Lexer) skipWhitespace() {
for l.ch == ' ' || l.ch == '\t' || l.ch == '\n' || l.ch == '\r' {
if l.ch == '\n' {
l.line++
}
l.readChar()
}
}
func isDigit(ch rune) bool {
return '0' <= ch && ch <= '9'
}
func (l *Lexer) readNumber() string {
position := l.position
for isDigit(l.ch) {
l.readChar()
}
return string(l.input[position:l.position])
}
func (l *Lexer) readDecimal() token.Token {
integer := l.readNumber()
if l.ch == '.' && isDigit(l.peekChar()) {
l.readChar()
fraction := l.readNumber()
return token.Token{Type: token.FLOAT, Literal: integer + "." + fraction, Line: l.line}
}
return token.Token{Type: token.INT, Literal: integer, Line: l.line}
}
func (l *Lexer) peekChar() rune {
if l.readPosition >= len(l.input) {
return rune(0)
} else {
return l.input[l.readPosition]
}
}
// func (l *Lexer) peekTwoChar() rune {
// if l.readPosition+1 >= len(l.input) {
// return rune(0)
// } else {
// return l.input[l.readPosition+1]
// }
// }
func (l *Lexer) skipSingleLineComment() {
for l.ch != '\n' && l.ch != 0 {
l.readChar()
}
l.skipWhitespace()
}
func (l *Lexer) skipMultiLineComment() {
endFound := false
for !endFound {
if l.ch == 0 {
endFound = true
}
if l.ch == '*' && l.peekChar() == '/' {
endFound = true
l.readChar()
}
l.readChar()
l.skipWhitespace()
}
}
func (l *Lexer) readString() string {
var str string
for {
l.readChar()
if l.ch == '"' || l.ch == 0 {
break
} else if l.ch == '\\' {
switch l.peekChar() {
case 'n':
l.readChar()
l.ch = '\n'
case 'r':
l.readChar()
l.ch = '\r'
case 't':
l.readChar()
l.ch = '\t'
case '"':
l.readChar()
l.ch = '"'
case '\\':
l.readChar()
l.ch = '\\'
}
}
str += string(l.ch)
}
return str
}
func (l *Lexer) readSingleQuoteString() string {
var str string
for {
l.readChar()
if l.ch == '\'' || l.ch == 0 {
break
} else if l.ch == '\\' {
switch l.peekChar() {
case 'n':
l.readChar()
l.ch = '\n'
case 'r':
l.readChar()
l.ch = '\r'
case 't':
l.readChar()
l.ch = '\t'
case '"':
l.readChar()
l.ch = '"'
case '\\':
l.readChar()
l.ch = '\\'
}
}
str += string(l.ch)
}
return str
}
================================================
FILE: lexer/lexer_test.go
================================================
package lexer
import (
"testing"
"github.com/NuruProgramming/Nuru/token"
)
func TestNextToken(t *testing.T) {
input := `
// Testing kama lex luther iko sawa
fanya tano = 5;
fanya kumi = 10;
fanya jumla = unda(x, y){
x + y;
};
fanya jibu = jumla(tano, kumi);
!-/5;
5 < 10 > 5;
kama (5 < 10) {
rudisha kweli;
} sivyo {
rudisha sikweli;
}
10 == 10;
10 != 9; // Hii ni comment
// Comment nyingine
/*
multiline comment
*/
/* multiline comment number twooooooooooo */
5
"bangi"
"ba ngi"
[1, 2];
{"mambo": "vipi"}
. // test dot
tumia muda
badili (a) {
ikiwa 2 {
andika(2)
}
kawaida {
andika(0)
}
}
tupu
kwa i, v ktk j`
tests := []struct {
expectedType token.TokenType
expectedLiteral string
}{
{token.LET, "fanya"},
{token.IDENT, "tano"},
{token.ASSIGN, "="},
{token.INT, "5"},
{token.SEMICOLON, ";"},
{token.LET, "fanya"},
{token.IDENT, "kumi"},
{token.ASSIGN, "="},
{token.INT, "10"},
{token.SEMICOLON, ";"},
{token.LET, "fanya"},
{token.IDENT, "jumla"},
{token.ASSIGN, "="},
{token.FUNCTION, "unda"},
{token.LPAREN, "("},
{token.IDENT, "x"},
{token.COMMA, ","},
{token.IDENT, "y"},
{token.RPAREN, ")"},
{token.LBRACE, "{"},
{token.IDENT, "x"},
{token.PLUS, "+"},
{token.IDENT, "y"},
{token.SEMICOLON, ";"},
{token.RBRACE, "}"},
{token.SEMICOLON, ";"},
{token.LET, "fanya"},
{token.IDENT, "jibu"},
{token.ASSIGN, "="},
{token.IDENT, "jumla"},
{token.LPAREN, "("},
{token.IDENT, "tano"},
{token.COMMA, ","},
{token.IDENT, "kumi"},
{token.RPAREN, ")"},
{token.SEMICOLON, ";"},
{token.BANG, "!"},
{token.MINUS, "-"},
{token.SLASH, "/"},
{token.INT, "5"},
{token.SEMICOLON, ";"},
{token.INT, "5"},
{token.LT, "<"},
{token.INT, "10"},
{token.GT, ">"},
{token.INT, "5"},
{token.SEMICOLON, ";"},
{token.IF, "kama"},
{token.LPAREN, "("},
{token.INT, "5"},
{token.LT, "<"},
{token.INT, "10"},
{token.RPAREN, ")"},
{token.LBRACE, "{"},
{token.RETURN, "rudisha"},
{token.TRUE, "kweli"},
{token.SEMICOLON, ";"},
{token.RBRACE, "}"},
{token.ELSE, "sivyo"},
{token.LBRACE, "{"},
{token.RETURN, "rudisha"},
{token.FALSE, "sikweli"},
{token.SEMICOLON, ";"},
{token.RBRACE, "}"},
{token.INT, "10"},
{token.EQ, "=="},
{token.INT, "10"},
{token.SEMICOLON, ";"},
{token.INT, "10"},
{token.NOT_EQ, "!="},
{token.INT, "9"},
{token.SEMICOLON, ";"},
{token.INT, "5"},
{token.STRING, "bangi"},
{token.STRING, "ba ngi"},
{token.LBRACKET, "["},
{token.INT, "1"},
{token.COMMA, ","},
{token.INT, "2"},
{token.RBRACKET, "]"},
{token.SEMICOLON, ";"},
{token.LBRACE, "{"},
{token.STRING, "mambo"},
{token.COLON, ":"},
{token.STRING, "vipi"},
{token.RBRACE, "}"},
{token.DOT, "."},
{token.IMPORT, "tumia"},
{token.IDENT, "muda"},
{token.SWITCH, "badili"},
{token.LPAREN, "("},
{token.IDENT, "a"},
{token.RPAREN, ")"},
{token.LBRACE, "{"},
{token.CASE, "ikiwa"},
{token.INT, "2"},
{token.LBRACE, "{"},
{token.IDENT, "andika"},
{token.LPAREN, "("},
{token.INT, "2"},
{token.RPAREN, ")"},
{token.RBRACE, "}"},
{token.DEFAULT, "kawaida"},
{token.LBRACE, "{"},
{token.IDENT, "andika"},
{token.LPAREN, "("},
{token.INT, "0"},
{token.RPAREN, ")"},
{token.RBRACE, "}"},
{token.RBRACE, "}"},
{token.NULL, "tupu"},
{token.FOR, "kwa"},
{token.IDENT, "i"},
{token.COMMA, ","},
{token.IDENT, "v"},
{token.IN, "ktk"},
{token.IDENT, "j"},
{token.EOF, ""},
}
l := New(input)
for i, tt := range tests {
tok := l.NextToken()
if tok.Type != tt.expectedType {
t.Fatalf("tests[%d] - tokentype wrong. expected=%q, got=%q",
i, tt.expectedType, tok.Type)
}
if tok.Literal != tt.expectedLiteral {
t.Fatalf("tests[%d] - literal wrong. expected=%q, got=%q",
i, tt.expectedLiteral, tok.Literal)
}
}
}
================================================
FILE: main.go
================================================
//go:build !wasm || !js
package main
import (
"fmt"
"os"
"strings"
"github.com/NuruProgramming/Nuru/repl"
"github.com/NuruProgramming/Nuru/styles"
"github.com/charmbracelet/lipgloss"
)
var (
Title = styles.TitleStyle.
Render(`
█░░ █░█ █▀▀ █░█ ▄▀█ █▄█ ▄▀█ █▄░█ █░█ █▀█ █░█
█▄▄ █▄█ █▄█ █▀█ █▀█ ░█░ █▀█ █░▀█ █▄█ █▀▄ █▄█`)
Version = styles.VersionStyle.Render("v0.5.18")
Author = styles.AuthorStyle.Render("by Nuru Org")
NewLogo = lipgloss.JoinVertical(lipgloss.Center, Title, lipgloss.JoinHorizontal(lipgloss.Center, Author, " | ", Version))
Help = styles.HelpStyle.Italic(false).Render(fmt.Sprintf(`💡 Namna ya kutumia Nuru:
%s: Kuanza programu ya Nuru
%s: Kuendesha faili la Nuru
%s: Kusoma nyaraka za Nuru
%s: Kufahamu toleo la Nuru
`,
styles.HelpStyle.Bold(true).Render("nuru"),
styles.HelpStyle.Bold(true).Render("nuru jinaLaFile.nr"),
styles.HelpStyle.Bold(true).Render("nuru --nyaraka"),
styles.HelpStyle.Bold(true).Render("nuru --toleo")))
)
func main() {
args := os.Args
if len(args) < 2 {
help := styles.HelpStyle.Render("💡 Tumia exit() au toka() kuondoka")
fmt.Println(lipgloss.JoinVertical(lipgloss.Left, NewLogo, "\n", help))
repl.Start()
return
}
if len(args) == 2 {
switch args[1] {
case "msaada", "-msaada", "--msaada", "help", "-help", "--help", "-h":
fmt.Println(Help)
case "version", "-version", "--version", "-v", "v", "--toleo", "-toleo":
fmt.Println(NewLogo)
case "-docs", "--docs", "-nyaraka", "--nyaraka":
repl.Docs()
default:
file := args[1]
if strings.HasSuffix(file, "nr") || strings.HasSuffix(file, ".sw") {
contents, err := os.ReadFile(file)
if err != nil {
fmt.Println(styles.ErrorStyle.Render("Error: Nuru imeshindwa kusoma faili: ", args[1]))
os.Exit(1)
}
repl.Read(string(contents))
} else {
fmt.Println(styles.ErrorStyle.Render("'"+file+"'", "sii faili sahihi. Tumia faili la '.nr' au '.sw'"))
os.Exit(1)
}
}
} else {
fmt.Println(styles.ErrorStyle.Render("Error: Operesheni imeshindikana boss."))
fmt.Println(Help)
os.Exit(1)
}
}
================================================
FILE: main_wasm.go
================================================
//go:build wasm && js
package main
import (
"fmt"
"github.com/NuruProgramming/Nuru/evaluator"
"github.com/NuruProgramming/Nuru/lexer"
"github.com/NuruProgramming/Nuru/object"
"github.com/NuruProgramming/Nuru/parser"
"syscall/js"
)
func Read(contents string) {
jsOutputReceiverFunction := js.Global().Get("nuruOutputReceiver")
env := object.NewEnvironment()
l := lexer.New(contents)
p := parser.New(l)
program := p.ParseProgram()
if len(p.Errors()) != 0 {
fmt.Println("Kuna makosa yafuatayo:")
jsOutputReceiverFunction.Invoke("Kuna makosa yafuatayo:", true)
for _, msg := range p.Errors() {
// fmt.Println("\t" + msg)
jsOutputReceiverFunction.Invoke("\t" + msg, true)
}
}
evaluated := evaluator.Eval(program, env)
if evaluated != nil {
if evaluated.Type() != object.NULL_OBJ {
jsOutputReceiverFunction.Invoke(evaluated.Inspect(), true)
}
}
}
func runCode(this js.Value, args []js.Value) interface{} {
code := args[0].String()
Read(code)
return nil
}
func main() {
fmt.Println("Go WASM initialized")
js.Global().Set("runCode", js.FuncOf(runCode))
<-make(chan bool)
}
================================================
FILE: module/hisabati.go
================================================
package module
import (
"math"
"math/rand"
"time"
"github.com/NuruProgramming/Nuru/object"
)
var MathFunctions = map[string]object.ModuleFunction{
"PI": pi,
"e": e,
"phi": phi,
"ln10": ln10,
"ln2": ln2,
"log10e": log10e,
"log2e": log2e,
"log2": log2,
"sqrt1_2": sqrt1_2,
"sqrt2": sqrt2,
"sqrt3": sqrt3,
"sqrt5": sqrt5,
"EPSILON": epsilon,
"abs": abs,
"sign": sign,
"ceil": ceil,
"floor": floor,
"sqrt": sqrt,
"cbrt": cbrt,
"root": root,
"hypot": hypot,
"random": random,
"factorial": factorial,
"round": round,
"max": max,
"min": min,
"exp": exp,
"expm1": expm1,
"log": log,
"log10": log10,
"log1p": log1p,
"cos": cos,
"sin": sin,
"tan": tan,
"acos": acos,
"asin": asin,
"atan": atan,
"cosh": cosh,
"sinh": sinh,
"tanh": tanh,
"acosh": acosh,
"asinh": asinh,
"atanh": atanh,
"atan2": atan2,
}
var Constants = map[string]object.Object{
"PI": &object.Float{Value: math.Pi},
"e": &object.Float{Value: math.E},
"phi": &object.Float{Value: (1 + math.Sqrt(5)) / 2},
"ln10": &object.Float{Value: math.Log10E},
"ln2": &object.Float{Value: math.Ln2},
"log10e": &object.Float{Value: math.Log10E},
"log2e": &object.Float{Value: math.Log2E},
"sqrt1_2": &object.Float{Value: 1 / math.Sqrt2},
"sqrt2": &object.Float{Value: math.Sqrt2},
"sqrt3": &object.Float{Value: math.Sqrt(3)},
"sqrt5": &object.Float{Value: math.Sqrt(5)},
"EPSILON": &object.Float{Value: 2.220446049250313e-16},
}
func pi(args []object.Object, defs map[string]object.Object) object.Object {
return &object.Float{Value: math.Pi}
}
func e(args []object.Object, defs map[string]object.Object) object.Object {
return &object.Float{Value: math.E}
}
func phi(args []object.Object, defs map[string]object.Object) object.Object {
return &object.Float{Value: (1 + math.Sqrt(5)) / 2}
}
func ln10(args []object.Object, defs map[string]object.Object) object.Object {
return &object.Float{Value: math.Log10E}
}
func ln2(args []object.Object, defs map[string]object.Object) object.Object {
return &object.Float{Value: math.Ln2}
}
func log10e(args []object.Object, defs map[string]object.Object) object.Object {
return &object.Float{Value: math.Log10E}
}
func log2e(args []object.Object, defs map[string]object.Object) object.Object {
return &object.Float{Value: math.Log2E}
}
func sqrt1_2(args []object.Object, defs map[string]object.Object) object.Object {
return &object.Float{Value: 1 / math.Sqrt2}
}
func sqrt2(args []object.Object, defs map[string]object.Object) object.Object {
return &object.Float{Value: math.Sqrt2}
}
func sqrt3(args []object.Object, defs map[string]object.Object) object.Object {
return &object.Float{Value: math.Sqrt(3)}
}
func sqrt5(args []object.Object, defs map[string]object.Object) object.Object {
return &object.Float{Value: math.Sqrt(5)}
}
func epsilon(args []object.Object, defs map[string]object.Object) object.Object {
return &object.Float{Value: 2.220446049250313e-16}
}
func abs(args []object.Object, defs map[string]object.Object) object.Object {
if len(defs) != 0 {
return &object.Error{Message: "Undo hili haliruhusu ufafanuzi."}
}
if len(args) != 1 {
return &object.Error{Message: "Undo hili linahitaji hoja moja tu"}
}
if args[0].Type() != object.INTEGER_OBJ && args[0].Type() != object.FLOAT_OBJ {
return &object.Error{Message: "Hoja lazima iwe namba"}
}
switch arg := args[0].(type) {
case *object.Integer:
if arg.Value < 0 {
return &object.Integer{Value: -arg.Value}
}
return arg
case *object.Float:
if arg.Value < 0 {
return &object.Float{Value: -arg.Value}
}
return arg
default:
return &object.Error{Message: "Hoja lazima iwe namba"}
}
}
func sign(args []object.Object, defs map[string]object.Object) object.Object {
if len(defs) != 0 {
return &object.Error{Message: "Undo hili haliruhusu ufafanuzi."}
}
if len(args) != 1 {
return &object.Error{Message: "Undo hili linahitaji hoja moja tu"}
}
switch arg := args[0].(type) {
case *object.Integer:
if arg.Value == 0 {
return &object.Integer{Value: 0}
} else if arg.Value > 0 {
return &object.Integer{Value: 1}
} else {
return &object.Integer{Value: -1}
}
case *object.Float:
if arg.Value == 0 {
return &object.Integer{Value: 0}
} else if arg.Value > 0 {
return &object.Integer{Value: 1}
} else {
return &object.Integer{Value: -1}
}
default:
return &object.Error{Message: "Hoja lazima iwe namba"}
}
}
func ceil(args []object.Object, defs map[string]object.Object) object.Object {
if len(defs) != 0 {
return &object.Error{Message: "Undo hili haliruhusu ufafanuzi."}
}
if len(args) != 1 {
return &object.Error{Message: "Undo hili linahitaji hoja moja tu"}
}
if args[0].Type() != object.INTEGER_OBJ && args[0].Type() != object.FLOAT_OBJ {
return &object.Error{Message: "Hoja lazima iwe namba"}
}
switch arg := args[0].(type) {
case *object.Integer:
return &object.Integer{Value: arg.Value}
case *object.Float:
return &object.Integer{Value: int64(math.Ceil(arg.Value))}
default:
return &object.Error{Message: "Hoja lazima iwe namba"}
}
}
func floor(args []object.Object, defs map[string]object.Object) object.Object {
if len(defs) != 0 {
return &object.Error{Message: "Undo hili haliruhusu ufafanuzi."}
}
if len(args) != 1 {
return &object.Error{Message: "Undo hili linahitaji hoja moja tu"}
}
if args[0].Type() != object.INTEGER_OBJ && args[0].Type() != object.FLOAT_OBJ {
return &object.Error{Message: "Hoja lazima iwe namba"}
}
switch arg := args[0].(type) {
case *object.Integer:
return &object.Integer{Value: arg.Value}
case *object.Float:
return &object.Integer{Value: int64(math.Floor(arg.Value))}
default:
return &object.Error{Message: "Hoja lazima iwe namba"}
}
}
func sqrt(args []object.Object, defs map[string]object.Object) object.Object {
if len(defs) != 0 {
return &object.Error{Message: "Undo hili haliruhusu ufafanuzi."}
}
if len(args) != 1 {
return &object.Error{Message: "Undo hili linahitaji hoja moja tu"}
}
if args[0].Type() != object.INTEGER_OBJ && args[0].Type() != object.FLOAT_OBJ {
return &object.Error{Message: "Hoja lazima iwe namba"}
}
switch arg := args[0].(type) {
case *object.Integer:
return &object.Float{Value: math.Sqrt(float64(arg.Value))}
case *object.Float:
return &object.Float{Value: math.Sqrt(arg.Value)}
default:
return &object.Error{Message: "Hoja lazima iwe namba"}
}
}
func cbrt(args []object.Object, defs map[string]object.Object) object.Object {
if len(defs) != 0 {
return &object.Error{Message: "Undo hili haliruhusu ufafanuzi."}
}
if len(args) != 1 {
return &object.Error{Message: "Undo hili linahitaji hoja moja tu"}
}
if args[0].Type() != object.INTEGER_OBJ && args[0].Type() != object.FLOAT_OBJ {
gitextract_yf7p31zd/ ├── .github/ │ ├── ISSUE_TEMPLATE/ │ │ ├── bug-report.yml │ │ └── feature-request.yml │ ├── PULL_REQUEST_TEMPLATE │ └── workflows/ │ ├── build.yml │ └── tests.yml ├── .gitignore ├── .goreleaser.yaml ├── ABOUT.md ├── LICENSE ├── Makefile ├── README.md ├── ast/ │ ├── ast.go │ └── ast_test.go ├── evaluator/ │ ├── assign.go │ ├── assignEqual.go │ ├── at.go │ ├── bang.go │ ├── block.go │ ├── builtins.go │ ├── builtins_common.go │ ├── builtins_wasm.go │ ├── call.go │ ├── dict.go │ ├── error_handler.go │ ├── evaluator.go │ ├── evaluator_test.go │ ├── forin.go │ ├── function.go │ ├── identifier.go │ ├── if.go │ ├── import.go │ ├── in.go │ ├── index.go │ ├── infix.go │ ├── method.go │ ├── package.go │ ├── postfix.go │ ├── prefix.go │ ├── property.go │ ├── switch.go │ ├── type.go │ └── while.go ├── examples/ │ ├── Astart.nr │ ├── example.nr │ ├── perceptron.nr │ ├── reduce.nr │ ├── sarufi.nr │ ├── sorting_algorithm.nr │ └── sudoku_solver.nr ├── extensions/ │ ├── README.md │ ├── vim/ │ │ └── syntax/ │ │ └── nuru.vim │ └── vscode/ │ ├── CHANGELOG.md │ └── README.md ├── go.mod ├── go.sum ├── gotest ├── lexer/ │ ├── lexer.go │ └── lexer_test.go ├── main.go ├── main_wasm.go ├── module/ │ ├── hisabati.go │ ├── json.go │ ├── module.go │ ├── net.go │ ├── os.go │ └── time.go ├── object/ │ ├── array.go │ ├── at.go │ ├── bool.go │ ├── break.go │ ├── builtin.go │ ├── byte.go │ ├── continue.go │ ├── dict.go │ ├── environment.go │ ├── error.go │ ├── error_wasm.go │ ├── file.go │ ├── float.go │ ├── function.go │ ├── instance.go │ ├── integer.go │ ├── module.go │ ├── null.go │ ├── object.go │ ├── object_test.go │ ├── package.go │ ├── return.go │ ├── strings.go │ └── time.go ├── parser/ │ ├── arrays.go │ ├── assignEqual.go │ ├── assignment.go │ ├── at.go │ ├── boolean.go │ ├── break.go │ ├── continue.go │ ├── dict.go │ ├── dot.go │ ├── float.go │ ├── for.go │ ├── function.go │ ├── identifier.go │ ├── if.go │ ├── import.go │ ├── index.go │ ├── integer.go │ ├── null.go │ ├── package.go │ ├── parser.go │ ├── parser_test.go │ ├── statements.go │ ├── string.go │ ├── switch.go │ └── while.go ├── repl/ │ ├── docs/ │ │ ├── en/ │ │ │ ├── README.md │ │ │ ├── arrays.md │ │ │ ├── bool.md │ │ │ ├── builtins.md │ │ │ ├── comments.md │ │ │ ├── dictionaries.md │ │ │ ├── files.md │ │ │ ├── for.md │ │ │ ├── function.md │ │ │ ├── hisabati.md │ │ │ ├── identifiers.md │ │ │ ├── ifStatements.md │ │ │ ├── json.md │ │ │ ├── keywords.md │ │ │ ├── net.md │ │ │ ├── null.md │ │ │ ├── numbers.md │ │ │ ├── operators.md │ │ │ ├── packages.md │ │ │ ├── range.md │ │ │ ├── strings.md │ │ │ ├── switch.md │ │ │ ├── time.md │ │ │ └── while.md │ │ └── sw/ │ │ ├── README.md │ │ ├── arrays.md │ │ ├── bools.md │ │ ├── builtins.md │ │ ├── dictionaries.md │ │ ├── for.md │ │ ├── functions.md │ │ ├── identifiers.md │ │ ├── if.md │ │ ├── keywords.md │ │ ├── maoni.md │ │ ├── null.md │ │ ├── numbers.md │ │ ├── operators.md │ │ ├── range.md │ │ ├── strings.md │ │ ├── switch.md │ │ └── while.md │ ├── docs.go │ └── repl.go ├── sh/ │ └── install.sh ├── styles/ │ └── styles.go ├── third_party/ │ └── math/ │ ├── README.md │ ├── hesabu.nr │ └── test.nr ├── token/ │ └── token.go └── upx
SYMBOL INDEX (654 symbols across 93 files)
FILE: ast/ast.go
type Node (line 10) | type Node interface
type Statement (line 15) | type Statement interface
type Expression (line 20) | type Expression interface
type Program (line 25) | type Program struct
method TokenLiteral (line 29) | func (p *Program) TokenLiteral() string {
method String (line 37) | func (p *Program) String() string {
type LetStatement (line 47) | type LetStatement struct
method statementNode (line 53) | func (ls *LetStatement) statementNode() {}
method TokenLiteral (line 54) | func (ls *LetStatement) TokenLiteral() string { return ls.Token.Literal }
method String (line 55) | func (ls *LetStatement) String() string {
type Identifier (line 70) | type Identifier struct
method expressionNode (line 75) | func (i *Identifier) expressionNode() {}
method TokenLiteral (line 76) | func (i *Identifier) TokenLiteral() string { return i.Token.Literal }
method String (line 77) | func (i *Identifier) String() string { return i.Value }
type ReturnStatement (line 79) | type ReturnStatement struct
method statementNode (line 84) | func (rs *ReturnStatement) statementNode() {}
method TokenLiteral (line 85) | func (rs *ReturnStatement) TokenLiteral() string { return rs.Token.Lit...
method String (line 86) | func (rs *ReturnStatement) String() string {
type ExpressionStatement (line 98) | type ExpressionStatement struct
method statementNode (line 103) | func (es *ExpressionStatement) statementNode() {}
method TokenLiteral (line 104) | func (es *ExpressionStatement) TokenLiteral() string { return es.Token...
method String (line 105) | func (es *ExpressionStatement) String() string {
type IntegerLiteral (line 113) | type IntegerLiteral struct
method expressionNode (line 118) | func (il *IntegerLiteral) expressionNode() {}
method TokenLiteral (line 119) | func (il *IntegerLiteral) TokenLiteral() string { return il.Token.Lite...
method String (line 120) | func (il *IntegerLiteral) String() string { return il.Token.Lite...
type PrefixExpression (line 122) | type PrefixExpression struct
method expressionNode (line 128) | func (pe *PrefixExpression) expressionNode() {}
method TokenLiteral (line 129) | func (pe *PrefixExpression) TokenLiteral() string { return pe.Token.Li...
method String (line 130) | func (pe *PrefixExpression) String() string {
type InfixExpression (line 141) | type InfixExpression struct
method expressionNode (line 148) | func (oe *InfixExpression) expressionNode() {}
method TokenLiteral (line 149) | func (oe *InfixExpression) TokenLiteral() string { return oe.Token.Lit...
method String (line 150) | func (oe *InfixExpression) String() string {
type Boolean (line 162) | type Boolean struct
method expressionNode (line 167) | func (b *Boolean) expressionNode() {}
method TokenLiteral (line 168) | func (b *Boolean) TokenLiteral() string { return b.Token.Literal }
method String (line 169) | func (b *Boolean) String() string { return b.Token.Literal }
type IfExpression (line 171) | type IfExpression struct
method expressionNode (line 178) | func (ie *IfExpression) expressionNode() {}
method TokenLiteral (line 179) | func (ie *IfExpression) TokenLiteral() string { return ie.Token.Literal }
method String (line 180) | func (ie *IfExpression) String() string {
type BlockStatement (line 195) | type BlockStatement struct
method statementNode (line 200) | func (bs *BlockStatement) statementNode() {}
method TokenLiteral (line 201) | func (bs *BlockStatement) TokenLiteral() string { return bs.Token.Lite...
method String (line 202) | func (bs *BlockStatement) String() string {
type FunctionLiteral (line 212) | type FunctionLiteral struct
method expressionNode (line 220) | func (fl *FunctionLiteral) expressionNode() {}
method TokenLiteral (line 221) | func (fl *FunctionLiteral) TokenLiteral() string { return fl.Token.Lit...
method String (line 222) | func (fl *FunctionLiteral) String() string {
type CallExpression (line 240) | type CallExpression struct
method expressionNode (line 246) | func (ce *CallExpression) expressionNode() {}
method TokenLiteral (line 247) | func (ce *CallExpression) TokenLiteral() string { return ce.Token.Lite...
method String (line 248) | func (ce *CallExpression) String() string {
type StringLiteral (line 264) | type StringLiteral struct
method expressionNode (line 269) | func (sl *StringLiteral) expressionNode() {}
method TokenLiteral (line 270) | func (sl *StringLiteral) TokenLiteral() string { return sl.Token.Liter...
method String (line 271) | func (sl *StringLiteral) String() string { return sl.Token.Liter...
type ArrayLiteral (line 273) | type ArrayLiteral struct
method expressionNode (line 278) | func (al *ArrayLiteral) expressionNode() {}
method TokenLiteral (line 279) | func (al *ArrayLiteral) TokenLiteral() string { return al.Token.Literal }
method String (line 280) | func (al *ArrayLiteral) String() string {
type IndexExpression (line 295) | type IndexExpression struct
method expressionNode (line 301) | func (ie *IndexExpression) expressionNode() {}
method TokenLiteral (line 302) | func (ie *IndexExpression) TokenLiteral() string { return ie.Token.Lit...
method String (line 303) | func (ie *IndexExpression) String() string {
type DictLiteral (line 315) | type DictLiteral struct
method expressionNode (line 320) | func (dl *DictLiteral) expressionNode() {}
method TokenLiteral (line 321) | func (dl *DictLiteral) TokenLiteral() string { return dl.Token.Literal }
method String (line 322) | func (dl *DictLiteral) String() string {
type Assign (line 336) | type Assign struct
method expressionNode (line 342) | func (ae *Assign) expressionNode() {}
method TokenLiteral (line 343) | func (ae *Assign) TokenLiteral() string { return ae.Token.Literal }
method String (line 344) | func (ae *Assign) String() string {
type AssignEqual (line 354) | type AssignEqual struct
method expressionNode (line 360) | func (ae *AssignEqual) expressionNode() {}
method TokenLiteral (line 361) | func (ae *AssignEqual) TokenLiteral() string { return ae.Token.Literal }
method String (line 362) | func (ae *AssignEqual) String() string {
type AssignmentExpression (line 372) | type AssignmentExpression struct
method expressionNode (line 378) | func (ae *AssignmentExpression) expressionNode() {}
method TokenLiteral (line 379) | func (ae *AssignmentExpression) TokenLiteral() string { return ae.Toke...
method String (line 380) | func (ae *AssignmentExpression) String() string {
type WhileExpression (line 390) | type WhileExpression struct
method expressionNode (line 396) | func (we *WhileExpression) expressionNode() {}
method TokenLiteral (line 397) | func (we *WhileExpression) TokenLiteral() string { return we.Token.Lit...
method String (line 398) | func (we *WhileExpression) String() string {
type Null (line 409) | type Null struct
method expressionNode (line 413) | func (n *Null) expressionNode() {}
method TokenLiteral (line 414) | func (n *Null) TokenLiteral() string { return n.Token.Literal }
method String (line 415) | func (n *Null) String() string { return n.Token.Literal }
type Break (line 417) | type Break struct
method expressionNode (line 422) | func (b *Break) expressionNode() {}
method TokenLiteral (line 423) | func (b *Break) TokenLiteral() string { return b.Token.Literal }
method String (line 424) | func (b *Break) String() string { return b.Token.Literal }
type Continue (line 426) | type Continue struct
method expressionNode (line 431) | func (c *Continue) expressionNode() {}
method TokenLiteral (line 432) | func (c *Continue) TokenLiteral() string { return c.Token.Literal }
method String (line 433) | func (c *Continue) String() string { return c.Token.Literal }
type PostfixExpression (line 435) | type PostfixExpression struct
method expressionNode (line 440) | func (pe *PostfixExpression) expressionNode() {}
method TokenLiteral (line 441) | func (pe *PostfixExpression) TokenLiteral() string { return pe.Token.L...
method String (line 442) | func (pe *PostfixExpression) String() string {
type FloatLiteral (line 451) | type FloatLiteral struct
method expressionNode (line 456) | func (fl *FloatLiteral) expressionNode() {}
method TokenLiteral (line 457) | func (fl *FloatLiteral) TokenLiteral() string { return fl.Token.Literal }
method String (line 458) | func (fl *FloatLiteral) String() string { return fl.Token.Literal }
type For (line 460) | type For struct
type ForIn (line 470) | type ForIn struct
method expressionNode (line 478) | func (fi *ForIn) expressionNode() {}
method TokenLiteral (line 479) | func (fi *ForIn) TokenLiteral() string { return fi.Token.Literal }
method String (line 480) | func (fi *ForIn) String() string {
type CaseExpression (line 496) | type CaseExpression struct
method expressionNode (line 503) | func (ce *CaseExpression) expressionNode() {}
method TokenLiteral (line 504) | func (ce *CaseExpression) TokenLiteral() string { return ce.Token.Lite...
method String (line 505) | func (ce *CaseExpression) String() string {
type SwitchExpression (line 523) | type SwitchExpression struct
method expressionNode (line 529) | func (se *SwitchExpression) expressionNode() {}
method TokenLiteral (line 530) | func (se *SwitchExpression) TokenLiteral() string { return se.Token.Li...
method String (line 531) | func (se *SwitchExpression) String() string {
type MethodExpression (line 547) | type MethodExpression struct
method expressionNode (line 555) | func (me *MethodExpression) expressionNode() {}
method TokenLiteral (line 556) | func (me *MethodExpression) TokenLiteral() string { return me.Token.Li...
method String (line 557) | func (me *MethodExpression) String() string {
type Import (line 566) | type Import struct
method expressionNode (line 571) | func (i *Import) expressionNode() {}
method TokenLiteral (line 572) | func (i *Import) TokenLiteral() string { return i.Token.Literal }
method String (line 573) | func (i *Import) String() string {
type PackageBlock (line 582) | type PackageBlock struct
method statementNode (line 587) | func (pb *PackageBlock) statementNode() {}
method TokenLiteral (line 588) | func (pb *PackageBlock) TokenLiteral() string { return pb.Token.Literal }
method String (line 589) | func (pb *PackageBlock) String() string {
type Package (line 599) | type Package struct
method expressionNode (line 605) | func (p *Package) expressionNode() {}
method TokenLiteral (line 606) | func (p *Package) TokenLiteral() string { return p.Token.Literal }
method String (line 607) | func (p *Package) String() string {
type At (line 620) | type At struct
method expressionNode (line 624) | func (a *At) expressionNode() {}
method TokenLiteral (line 625) | func (a *At) TokenLiteral() string { return a.Token.Literal }
method String (line 626) | func (a *At) String() string { return "@" }
type PropertyAssignment (line 628) | type PropertyAssignment struct
method expressionNode (line 634) | func (pa *PropertyAssignment) expressionNode() {}
method TokenLiteral (line 635) | func (pa *PropertyAssignment) TokenLiteral() string { return pa.Token....
method String (line 636) | func (pa *PropertyAssignment) String() string { return "Ngl I'm ...
type PropertyExpression (line 638) | type PropertyExpression struct
method expressionNode (line 645) | func (pe *PropertyExpression) expressionNode() {}
method TokenLiteral (line 646) | func (pe *PropertyExpression) TokenLiteral() string { return pe.Token....
method String (line 647) | func (pe *PropertyExpression) String() string { return "Ngl I'm ...
FILE: ast/ast_test.go
function TestString (line 9) | func TestString(t *testing.T) {
FILE: evaluator/assign.go
function evalAssign (line 8) | func evalAssign(node *ast.Assign, env *object.Environment) object.Object {
FILE: evaluator/assignEqual.go
function evalAssignEqual (line 10) | func evalAssignEqual(node *ast.AssignEqual, env *object.Environment) obj...
FILE: evaluator/at.go
function evalAt (line 8) | func evalAt(node *ast.At, env *object.Environment) object.Object {
FILE: evaluator/bang.go
function evalBangOperatorExpression (line 5) | func evalBangOperatorExpression(right object.Object) object.Object {
FILE: evaluator/block.go
function evalBlockStatement (line 8) | func evalBlockStatement(block *ast.BlockStatement, env *object.Environme...
FILE: evaluator/builtins.go
function init (line 79) | func init(){
FILE: evaluator/builtins_common.go
function getIntValue (line 194) | func getIntValue(obj object.Object) (int64, error) {
FILE: evaluator/builtins_wasm.go
function init (line 67) | func init(){
FILE: evaluator/call.go
function evalCall (line 8) | func evalCall(node *ast.CallExpression, env *object.Environment) object....
function evalArgsExpressions (line 37) | func evalArgsExpressions(node *ast.CallExpression, fn *object.Function, ...
FILE: evaluator/dict.go
function evalDictLiteral (line 8) | func evalDictLiteral(node *ast.DictLiteral, env *object.Environment) obj...
FILE: evaluator/error_handler.go
function newError (line 9) | func newError(format string, a ...interface{}) *object.Error {
FILE: evaluator/evaluator.go
function Eval (line 16) | func Eval(node ast.Node, env *object.Environment) object.Object {
function evalProgram (line 206) | func evalProgram(program *ast.Program, env *object.Environment) object.O...
function nativeBoolToBooleanObject (line 223) | func nativeBoolToBooleanObject(input bool) *object.Boolean {
function isTruthy (line 230) | func isTruthy(obj object.Object) bool {
function isError (line 243) | func isError(obj object.Object) bool {
function evalExpressions (line 251) | func evalExpressions(exps []ast.Expression, env *object.Environment) []o...
function applyFunction (line 266) | func applyFunction(fn object.Object, args []object.Object, line int) obj...
function extendedFunctionEnv (line 301) | func extendedFunctionEnv(fn *object.Function, args []object.Object) *obj...
function unwrapReturnValue (line 312) | func unwrapReturnValue(obj object.Object) object.Object {
function evalBreak (line 320) | func evalBreak(node *ast.Break) object.Object {
function evalContinue (line 324) | func evalContinue(node *ast.Continue) object.Object {
function loopIterable (line 379) | func loopIterable(next func() (object.Object, object.Object), env *objec...
FILE: evaluator/evaluator_test.go
function TestEvalIntegerExpression (line 13) | func TestEvalIntegerExpression(t *testing.T) {
function TestEvalFloatExpression (line 33) | func TestEvalFloatExpression(t *testing.T) {
function TestEvalBooleanExpression (line 47) | func TestEvalBooleanExpression(t *testing.T) {
function TestBangOperator (line 90) | func TestBangOperator(t *testing.T) {
function testEval (line 109) | func testEval(input string) object.Object {
function testIntegerObject (line 118) | func testIntegerObject(t *testing.T, obj object.Object, expected int64) ...
function testFloatObject (line 134) | func testFloatObject(t *testing.T, obj object.Object, expected float64) ...
function testBooleanObject (line 150) | func testBooleanObject(t *testing.T, obj object.Object, expected bool) b...
function TestIfElseExpressions (line 165) | func TestIfElseExpressions(t *testing.T) {
function testNullObject (line 190) | func testNullObject(t *testing.T, obj object.Object) bool {
function TestReturnStatements (line 198) | func TestReturnStatements(t *testing.T) {
function TestErrorHandling (line 215) | func TestErrorHandling(t *testing.T) {
function TestLetStatement (line 285) | func TestLetStatement(t *testing.T) {
function TestFunctionObject (line 301) | func TestFunctionObject(t *testing.T) {
function TestFunctionApplication (line 325) | func TestFunctionApplication(t *testing.T) {
function TestClosures (line 343) | func TestClosures(t *testing.T) {
function TestStringLiteral (line 355) | func TestStringLiteral(t *testing.T) {
function TestStringconcatenation (line 369) | func TestStringconcatenation(t *testing.T) {
function TestStringMultiplyInteger (line 384) | func TestStringMultiplyInteger(t *testing.T) {
function TestArrayLiterals (line 435) | func TestArrayLiterals(t *testing.T) {
function TestArrayIndexExpressions (line 453) | func TestArrayIndexExpressions(t *testing.T) {
function TestDictLiterals (line 499) | func TestDictLiterals(t *testing.T) {
function TestDictIndexExpression (line 539) | func TestDictIndexExpression(t *testing.T) {
function TestPrefixInteger (line 585) | func TestPrefixInteger(t *testing.T) {
function TestPrefixFloat (line 610) | func TestPrefixFloat(t *testing.T) {
function TestInExpression (line 635) | func TestInExpression(t *testing.T) {
function TestArrayConcatenation (line 676) | func TestArrayConcatenation(t *testing.T) {
function TestDictConcatenation (line 708) | func TestDictConcatenation(t *testing.T) {
function TestPostfixExpression (line 736) | func TestPostfixExpression(t *testing.T) {
function TestWhileLoop (line 783) | func TestWhileLoop(t *testing.T) {
function TestForLoop (line 803) | func TestForLoop(t *testing.T) {
function TestBreakLoop (line 822) | func TestBreakLoop(t *testing.T) {
function TestContinueLoop (line 865) | func TestContinueLoop(t *testing.T) {
function TestSwitchStatement (line 909) | func TestSwitchStatement(t *testing.T) {
function TestAssignEqual (line 987) | func TestAssignEqual(t *testing.T) {
function TestStringMethods (line 1061) | func TestStringMethods(t *testing.T) {
function TestTimeModule (line 1114) | func TestTimeModule(t *testing.T) {
FILE: evaluator/forin.go
function evalForInExpression (line 8) | func evalForInExpression(fie *ast.ForIn, env *object.Environment, line i...
FILE: evaluator/function.go
function evalFunction (line 8) | func evalFunction(node *ast.FunctionLiteral, env *object.Environment) ob...
FILE: evaluator/identifier.go
function evalIdentifier (line 8) | func evalIdentifier(node *ast.Identifier, env *object.Environment) objec...
FILE: evaluator/if.go
function evalIfExpression (line 8) | func evalIfExpression(ie *ast.IfExpression, env *object.Environment) obj...
FILE: evaluator/import.go
function evalImport (line 18) | func evalImport(node *ast.Import, env *object.Environment) object.Object {
function evalImportFile (line 29) | func evalImportFile(name string, ident *ast.Identifier, env *object.Envi...
function addSearchPath (line 43) | func addSearchPath(path string) {
function findFile (line 47) | func findFile(name string) string {
function fileExists (line 58) | func fileExists(file string) bool {
function evaluateFile (line 63) | func evaluateFile(file string, env *object.Environment) (*object.Environ...
function importFile (line 83) | func importFile(name string, ident *ast.Identifier, env *object.Environm...
FILE: evaluator/in.go
function evalInExpression (line 9) | func evalInExpression(left, right object.Object, line int) object.Object {
function evalInStringExpression (line 22) | func evalInStringExpression(left, right object.Object) object.Object {
function evalInDictExpression (line 32) | func evalInDictExpression(left, right object.Object, line int) object.Ob...
function evalInArrayExpression (line 43) | func evalInArrayExpression(left, right object.Object) object.Object {
FILE: evaluator/index.go
function evalIndexExpression (line 5) | func evalIndexExpression(left, index object.Object, line int) object.Obj...
function evalArrayIndexExpression (line 18) | func evalArrayIndexExpression(array, index object.Object) object.Object {
function evalDictIndexExpression (line 30) | func evalDictIndexExpression(dict, index object.Object, line int) object...
FILE: evaluator/infix.go
function evalInfixExpression (line 10) | func evalInfixExpression(operator string, left, right object.Object, lin...
function evalFloatIntegerInfixExpression (line 101) | func evalFloatIntegerInfixExpression(operator string, left, right object...
function evalStringInfixExpression (line 149) | func evalStringInfixExpression(operator string, left, right object.Objec...
function evalBooleanInfixExpression (line 166) | func evalBooleanInfixExpression(operator string, left, right object.Obje...
function evalFloatInfixExpression (line 180) | func evalFloatInfixExpression(operator string, left, right object.Object...
function evalIntegerInfixExpression (line 213) | func evalIntegerInfixExpression(operator string, left, right object.Obje...
FILE: evaluator/method.go
function evalMethodExpression (line 8) | func evalMethodExpression(node *ast.MethodExpression, env *object.Enviro...
function applyMethod (line 26) | func applyMethod(obj object.Object, method ast.Expression, args []object...
function maap (line 68) | func maap(a *object.Array, args []object.Object) object.Object {
function filter (line 90) | func filter(a *object.Array, args []object.Object) object.Object {
FILE: evaluator/package.go
function evalPackage (line 8) | func evalPackage(node *ast.Package, env *object.Environment) object.Obje...
FILE: evaluator/postfix.go
function evalPostfixExpression (line 8) | func evalPostfixExpression(env *object.Environment, operator string, nod...
FILE: evaluator/prefix.go
function evalMinusPrefixOperatorExpression (line 5) | func evalMinusPrefixOperatorExpression(right object.Object, line int) ob...
function evalPlusPrefixOperatorExpression (line 18) | func evalPlusPrefixOperatorExpression(right object.Object, line int) obj...
function evalPrefixExpression (line 32) | func evalPrefixExpression(operator string, right object.Object, line int...
FILE: evaluator/property.go
function evalPropertyExpression (line 8) | func evalPropertyExpression(node *ast.PropertyExpression, env *object.En...
function evalPropertyAssignment (line 36) | func evalPropertyAssignment(name *ast.PropertyExpression, val object.Obj...
FILE: evaluator/switch.go
function evalSwitchStatement (line 8) | func evalSwitchStatement(se *ast.SwitchExpression, env *object.Environme...
FILE: evaluator/type.go
function convertToInteger (line 9) | func convertToInteger(obj object.Object) object.Object {
function convertToFloat (line 31) | func convertToFloat(obj object.Object) object.Object {
function convertToString (line 53) | func convertToString(obj object.Object) object.Object {
function convertToBoolean (line 57) | func convertToBoolean(obj object.Object) object.Object {
FILE: evaluator/while.go
constant MAX_ITERATIONS (line 8) | MAX_ITERATIONS = 1_000_000
function evalWhileExpression (line 10) | func evalWhileExpression(we *ast.WhileExpression, env *object.Environmen...
FILE: lexer/lexer.go
type Lexer (line 9) | type Lexer struct
method readChar (line 23) | func (l *Lexer) readChar() {
method NextToken (line 34) | func (l *Lexer) NextToken() token.Token {
method readIdentifier (line 207) | func (l *Lexer) readIdentifier() string {
method skipWhitespace (line 220) | func (l *Lexer) skipWhitespace() {
method readNumber (line 233) | func (l *Lexer) readNumber() string {
method readDecimal (line 241) | func (l *Lexer) readDecimal() token.Token {
method peekChar (line 251) | func (l *Lexer) peekChar() rune {
method skipSingleLineComment (line 267) | func (l *Lexer) skipSingleLineComment() {
method skipMultiLineComment (line 274) | func (l *Lexer) skipMultiLineComment() {
method readString (line 293) | func (l *Lexer) readString() string {
method readSingleQuoteString (line 323) | func (l *Lexer) readSingleQuoteString() string {
function New (line 17) | func New(input string) *Lexer {
function newToken (line 203) | func newToken(tokenType token.TokenType, line int, ch rune) token.Token {
function isLetter (line 216) | func isLetter(ch rune) bool {
function isDigit (line 229) | func isDigit(ch rune) bool {
FILE: lexer/lexer_test.go
function TestNextToken (line 9) | func TestNextToken(t *testing.T) {
FILE: main.go
function main (line 35) | func main() {
FILE: main_wasm.go
function Read (line 16) | func Read(contents string) {
function runCode (line 45) | func runCode(this js.Value, args []js.Value) interface{} {
function main (line 51) | func main() {
FILE: module/hisabati.go
function pi (line 73) | func pi(args []object.Object, defs map[string]object.Object) object.Obje...
function e (line 77) | func e(args []object.Object, defs map[string]object.Object) object.Object {
function phi (line 81) | func phi(args []object.Object, defs map[string]object.Object) object.Obj...
function ln10 (line 85) | func ln10(args []object.Object, defs map[string]object.Object) object.Ob...
function ln2 (line 89) | func ln2(args []object.Object, defs map[string]object.Object) object.Obj...
function log10e (line 93) | func log10e(args []object.Object, defs map[string]object.Object) object....
function log2e (line 97) | func log2e(args []object.Object, defs map[string]object.Object) object.O...
function sqrt1_2 (line 101) | func sqrt1_2(args []object.Object, defs map[string]object.Object) object...
function sqrt2 (line 105) | func sqrt2(args []object.Object, defs map[string]object.Object) object.O...
function sqrt3 (line 109) | func sqrt3(args []object.Object, defs map[string]object.Object) object.O...
function sqrt5 (line 113) | func sqrt5(args []object.Object, defs map[string]object.Object) object.O...
function epsilon (line 117) | func epsilon(args []object.Object, defs map[string]object.Object) object...
function abs (line 121) | func abs(args []object.Object, defs map[string]object.Object) object.Obj...
function sign (line 147) | func sign(args []object.Object, defs map[string]object.Object) object.Ob...
function ceil (line 176) | func ceil(args []object.Object, defs map[string]object.Object) object.Ob...
function floor (line 196) | func floor(args []object.Object, defs map[string]object.Object) object.O...
function sqrt (line 216) | func sqrt(args []object.Object, defs map[string]object.Object) object.Ob...
function cbrt (line 236) | func cbrt(args []object.Object, defs map[string]object.Object) object.Ob...
function root (line 256) | func root(args []object.Object, defs map[string]object.Object) object.Ob...
function hypot (line 289) | func hypot(args []object.Object, defs map[string]object.Object) object.O...
function factorial (line 311) | func factorial(args []object.Object, defs map[string]object.Object) obje...
function round (line 332) | func round(args []object.Object, defs map[string]object.Object) object.O...
function max (line 347) | func max(args []object.Object, defs map[string]object.Object) object.Obj...
function min (line 388) | func min(args []object.Object, defs map[string]object.Object) object.Obj...
function exp (line 429) | func exp(args []object.Object, defs map[string]object.Object) object.Obj...
function expm1 (line 443) | func expm1(args []object.Object, defs map[string]object.Object) object.O...
function log (line 457) | func log(args []object.Object, defs map[string]object.Object) object.Obj...
function log10 (line 471) | func log10(args []object.Object, defs map[string]object.Object) object.O...
function log2 (line 485) | func log2(args []object.Object, defs map[string]object.Object) object.Ob...
function extractFloatValue (line 505) | func extractFloatValue(obj object.Object) float64 {
function log1p (line 516) | func log1p(args []object.Object, defs map[string]object.Object) object.O...
function cos (line 530) | func cos(args []object.Object, defs map[string]object.Object) object.Obj...
function sin (line 544) | func sin(args []object.Object, defs map[string]object.Object) object.Obj...
function tan (line 558) | func tan(args []object.Object, defs map[string]object.Object) object.Obj...
function acos (line 572) | func acos(args []object.Object, defs map[string]object.Object) object.Ob...
function asin (line 586) | func asin(args []object.Object, defs map[string]object.Object) object.Ob...
function atan (line 600) | func atan(args []object.Object, defs map[string]object.Object) object.Ob...
function cosh (line 614) | func cosh(args []object.Object, defs map[string]object.Object) object.Ob...
function sinh (line 628) | func sinh(args []object.Object, defs map[string]object.Object) object.Ob...
function tanh (line 642) | func tanh(args []object.Object, defs map[string]object.Object) object.Ob...
function acosh (line 656) | func acosh(args []object.Object, defs map[string]object.Object) object.O...
function asinh (line 670) | func asinh(args []object.Object, defs map[string]object.Object) object.O...
function atan2 (line 684) | func atan2(args []object.Object, defs map[string]object.Object) object.O...
function atanh (line 704) | func atanh(args []object.Object, defs map[string]object.Object) object.O...
function random (line 718) | func random(args []object.Object, defs map[string]object.Object) object....
FILE: module/json.go
function init (line 11) | func init() {
function decode (line 16) | func decode(args []object.Object, defs map[string]object.Object) object....
function convertWhateverToObject (line 39) | func convertWhateverToObject(i interface{}) object.Object {
function encode (line 77) | func encode(args []object.Object, defs map[string]object.Object) object....
function convertObjectToWhatever (line 93) | func convertObjectToWhatever(obj object.Object) interface{} {
FILE: module/module.go
function init (line 7) | func init() {
FILE: module/net.go
function init (line 14) | func init() {
function getRequest (line 19) | func getRequest(args []object.Object, defs map[string]object.Object) obj...
function postRequest (line 126) | func postRequest(args []object.Object, defs map[string]object.Object) ob...
FILE: module/os.go
function init (line 13) | func init() {
function exit (line 18) | func exit(args []object.Object, defs map[string]object.Object) object.Ob...
function run (line 37) | func run(args []object.Object, defs map[string]object.Object) object.Obj...
FILE: module/time.go
function init (line 13) | func init() {
function now (line 23) | func now(args []object.Object, defs map[string]object.Object) object.Obj...
function sleep (line 34) | func sleep(args []object.Object, defs map[string]object.Object) object.O...
function since (line 54) | func since(args []object.Object, defs map[string]object.Object) object.O...
function today (line 88) | func today(args []object.Object, defs map[string]object.Object) object.O...
function after (line 97) | func after(args []object.Object, defs map[string]object.Object) object.O...
function diff (line 112) | func diff(args []object.Object, defs map[string]object.Object) object.Ob...
function addTime (line 140) | func addTime(args []object.Object, defs map[string]object.Object) object...
function getInt (line 177) | func getInt(obj object.Object) int {
FILE: object/array.go
type Array (line 8) | type Array struct
method Type (line 13) | func (ao *Array) Type() ObjectType { return ARRAY_OBJ }
method Inspect (line 14) | func (ao *Array) Inspect() string {
method Next (line 33) | func (ao *Array) Next() (Object, Object) {
method Reset (line 42) | func (ao *Array) Reset() {
method Method (line 46) | func (a *Array) Method(method string, args []Object) Object {
method len (line 65) | func (a *Array) len(args []Object) Object {
method last (line 72) | func (a *Array) last() Object {
method push (line 80) | func (a *Array) push(args []Object) Object {
method join (line 85) | func (a *Array) join(args []Object) Object {
method filter (line 105) | func (a *Array) filter(args []Object) Object {
method find (line 120) | func (a *Array) find(args []Object) Object {
FILE: object/at.go
type At (line 5) | type At struct
method Type (line 9) | func (a *At) Type() ObjectType { return AT }
method Inspect (line 10) | func (a *At) Inspect() string {
FILE: object/bool.go
type Boolean (line 3) | type Boolean struct
method Inspect (line 7) | func (b *Boolean) Inspect() string {
method Type (line 14) | func (b *Boolean) Type() ObjectType { return BOOLEAN_OBJ }
method HashKey (line 16) | func (b *Boolean) HashKey() HashKey {
FILE: object/break.go
type Break (line 3) | type Break struct
method Type (line 5) | func (b *Break) Type() ObjectType { return BREAK_OBJ }
method Inspect (line 6) | func (b *Break) Inspect() string { return "break" }
FILE: object/builtin.go
type BuiltinFunction (line 3) | type BuiltinFunction
type Builtin (line 5) | type Builtin struct
method Inspect (line 9) | func (b *Builtin) Inspect() string { return "builtin function" }
method Type (line 10) | func (b *Builtin) Type() ObjectType { return BUILTIN_OBJ }
FILE: object/byte.go
type Byte (line 3) | type Byte struct
method Inspect (line 8) | func (b *Byte) Inspect() string { return "b" + b.String }
method Type (line 9) | func (b *Byte) Type() ObjectType { return BYTE_OBJ }
FILE: object/continue.go
type Continue (line 3) | type Continue struct
method Type (line 5) | func (c *Continue) Type() ObjectType { return CONTINUE_OBJ }
method Inspect (line 6) | func (c *Continue) Inspect() string { return "continue" }
FILE: object/dict.go
type DictPair (line 10) | type DictPair struct
type Dict (line 15) | type Dict struct
method Type (line 20) | func (d *Dict) Type() ObjectType { return DICT_OBJ }
method Inspect (line 21) | func (d *Dict) Inspect() string {
method Next (line 37) | func (d *Dict) Next() (Object, Object) {
method Reset (line 58) | func (d *Dict) Reset() {
FILE: object/environment.go
function NewEnclosedEnvironment (line 3) | func NewEnclosedEnvironment(outer *Environment) *Environment {
function NewEnvironment (line 9) | func NewEnvironment() *Environment {
type Environment (line 14) | type Environment struct
method Get (line 19) | func (e *Environment) Get(name string) (Object, bool) {
method Set (line 28) | func (e *Environment) Set(name string, val Object) Object {
method Del (line 33) | func (e *Environment) Del(name string) bool {
FILE: object/error.go
type Error (line 6) | type Error struct
method Inspect (line 10) | func (e *Error) Inspect() string {
method Type (line 14) | func (e *Error) Type() ObjectType { return ERROR_OBJ }
FILE: object/error_wasm.go
type Error (line 4) | type Error struct
method Inspect (line 8) | func (e *Error) Inspect() string {
method Type (line 12) | func (e *Error) Type() ObjectType { return ERROR_OBJ }
FILE: object/file.go
type File (line 7) | type File struct
method Type (line 12) | func (f *File) Type() ObjectType { return FILE_OBJ }
method Inspect (line 13) | func (f *File) Inspect() string { return f.Filename }
method Method (line 14) | func (f *File) Method(method string, args []Object) Object {
method read (line 26) | func (f *File) read(args []Object) Object {
method write (line 33) | func (f *File) write(args []Object) Object {
method append (line 49) | func (f *File) append(args []Object) Object {
FILE: object/float.go
type Float (line 8) | type Float struct
method Inspect (line 12) | func (f *Float) Inspect() string { return strconv.FormatFloat(f.Value...
method Type (line 13) | func (f *Float) Type() ObjectType { return FLOAT_OBJ }
method HashKey (line 15) | func (f *Float) HashKey() HashKey {
FILE: object/function.go
type Function (line 10) | type Function struct
method Type (line 18) | func (f *Function) Type() ObjectType { return FUNCTION_OBJ }
method Inspect (line 19) | func (f *Function) Inspect() string {
FILE: object/instance.go
type Instance (line 5) | type Instance struct
method Type (line 10) | func (i *Instance) Type() ObjectType { return INSTANCE }
method Inspect (line 11) | func (i *Instance) Inspect() string {
FILE: object/integer.go
type Integer (line 5) | type Integer struct
method Inspect (line 9) | func (i *Integer) Inspect() string { return fmt.Sprintf("%d", i.Value) }
method Type (line 10) | func (i *Integer) Type() ObjectType { return INTEGER_OBJ }
method HashKey (line 12) | func (i *Integer) HashKey() HashKey {
FILE: object/module.go
type ModuleFunction (line 3) | type ModuleFunction
type Module (line 5) | type Module struct
method Type (line 10) | func (m *Module) Type() ObjectType {
method Inspect (line 20) | func (m *Module) Inspect() string { return "Module: " + m.Name }
FILE: object/null.go
type Null (line 3) | type Null struct
method Inspect (line 5) | func (n *Null) Inspect() string { return "null" }
method Type (line 6) | func (n *Null) Type() ObjectType { return NULL_OBJ }
FILE: object/object.go
type ObjectType (line 7) | type ObjectType
constant INTEGER_OBJ (line 10) | INTEGER_OBJ = "NAMBA"
constant FLOAT_OBJ (line 11) | FLOAT_OBJ = "DESIMALI"
constant BOOLEAN_OBJ (line 12) | BOOLEAN_OBJ = "BOOLEAN"
constant NULL_OBJ (line 13) | NULL_OBJ = "TUPU"
constant RETURN_VALUE_OBJ (line 14) | RETURN_VALUE_OBJ = "RUDISHA"
constant ERROR_OBJ (line 15) | ERROR_OBJ = "KOSA"
constant FUNCTION_OBJ (line 16) | FUNCTION_OBJ = "UNDO (FUNCTION)"
constant STRING_OBJ (line 17) | STRING_OBJ = "NENO"
constant BUILTIN_OBJ (line 18) | BUILTIN_OBJ = "YA_NDANI"
constant ARRAY_OBJ (line 19) | ARRAY_OBJ = "ORODHA"
constant DICT_OBJ (line 20) | DICT_OBJ = "KAMUSI"
constant CONTINUE_OBJ (line 21) | CONTINUE_OBJ = "ENDELEA"
constant BREAK_OBJ (line 22) | BREAK_OBJ = "VUNJA"
constant FILE_OBJ (line 23) | FILE_OBJ = "FAILI"
constant TIME_OBJ (line 24) | TIME_OBJ = "MUDA"
constant JSON_OBJ (line 25) | JSON_OBJ = "JSONI"
constant MODULE_OBJ (line 26) | MODULE_OBJ = "MODULE"
constant BYTE_OBJ (line 27) | BYTE_OBJ = "BYTE"
constant PACKAGE_OBJ (line 28) | PACKAGE_OBJ = "PAKEJI"
constant INSTANCE (line 29) | INSTANCE = "PAKEJI"
constant AT (line 30) | AT = "@"
type Object (line 33) | type Object interface
type HashKey (line 38) | type HashKey struct
type Hashable (line 43) | type Hashable interface
type Iterable (line 48) | type Iterable interface
function newError (line 53) | func newError(format string, a ...interface{}) *Error {
FILE: object/object_test.go
function TestStringHashKey (line 5) | func TestStringHashKey(t *testing.T) {
FILE: object/package.go
type Package (line 9) | type Package struct
method Type (line 15) | func (p *Package) Type() ObjectType { return PACKAGE_OBJ }
method Inspect (line 16) | func (p *Package) Inspect() string {
FILE: object/return.go
type ReturnValue (line 3) | type ReturnValue struct
method Inspect (line 7) | func (rv *ReturnValue) Inspect() string { return rv.Value.Inspect() }
method Type (line 8) | func (rv *ReturnValue) Type() ObjectType { return RETURN_VALUE_OBJ }
FILE: object/strings.go
type String (line 10) | type String struct
method Inspect (line 15) | func (s *String) Inspect() string { return s.Value }
method Type (line 16) | func (s *String) Type() ObjectType { return STRING_OBJ }
method HashKey (line 17) | func (s *String) HashKey() HashKey {
method Next (line 23) | func (s *String) Next() (Object, Object) {
method Reset (line 31) | func (s *String) Reset() {
method Method (line 34) | func (s *String) Method(method string, args []Object) Object {
method len (line 51) | func (s *String) len(args []Object) Object {
method upper (line 58) | func (s *String) upper(args []Object) Object {
method lower (line 65) | func (s *String) lower(args []Object) Object {
method split (line 72) | func (s *String) split(args []Object) Object {
method format (line 89) | func (s *String) format(args []Object) Object {
function formatStr (line 99) | func formatStr(format string, options []Object) (string, error) {
FILE: object/time.go
type Time (line 9) | type Time struct
method Type (line 13) | func (t *Time) Type() ObjectType { return TIME_OBJ }
method Inspect (line 14) | func (t *Time) Inspect() string { return t.TimeValue }
method Method (line 15) | func (t *Time) Method(method string, args []Object, defs map[string]Ob...
method add (line 25) | func (t *Time) add(args []Object, defs map[string]Object) Object {
method since (line 77) | func (t *Time) since(args []Object, defs map[string]Object) Object {
FILE: parser/arrays.go
method parseArrayLiteral (line 8) | func (p *Parser) parseArrayLiteral() ast.Expression {
method parseExpressionList (line 16) | func (p *Parser) parseExpressionList(end token.TokenType) []ast.Expressi...
FILE: parser/assignEqual.go
method parseAssignEqualExpression (line 9) | func (p *Parser) parseAssignEqualExpression(exp ast.Expression) ast.Expr...
FILE: parser/assignment.go
method parseAssignmentExpression (line 9) | func (p *Parser) parseAssignmentExpression(exp ast.Expression) ast.Expre...
FILE: parser/at.go
method parseAt (line 5) | func (p *Parser) parseAt() ast.Expression {
FILE: parser/boolean.go
method parseBoolean (line 8) | func (p *Parser) parseBoolean() ast.Expression {
FILE: parser/break.go
method parseBreak (line 8) | func (p *Parser) parseBreak() *ast.Break {
FILE: parser/continue.go
method parseContinue (line 8) | func (p *Parser) parseContinue() *ast.Continue {
FILE: parser/dict.go
method parseDictLiteral (line 8) | func (p *Parser) parseDictLiteral() ast.Expression {
FILE: parser/dot.go
method parseMethod (line 8) | func (p *Parser) parseMethod(obj ast.Expression) ast.Expression {
FILE: parser/float.go
method parseFloatLiteral (line 10) | func (p *Parser) parseFloatLiteral() ast.Expression {
FILE: parser/for.go
method parseForExpression (line 8) | func (p *Parser) parseForExpression() ast.Expression {
method parseForInExpression (line 63) | func (p *Parser) parseForInExpression(initialExpression *ast.For) ast.Ex...
FILE: parser/function.go
method parseFunctionLiteral (line 8) | func (p *Parser) parseFunctionLiteral() ast.Expression {
method parseFunctionParameters (line 33) | func (p *Parser) parseFunctionParameters(lit *ast.FunctionLiteral) bool {
method parseCallExpression (line 63) | func (p *Parser) parseCallExpression(function ast.Expression) ast.Expres...
FILE: parser/identifier.go
method parseIdentifier (line 7) | func (p *Parser) parseIdentifier() ast.Expression {
FILE: parser/if.go
method parseIfExpression (line 8) | func (p *Parser) parseIfExpression() ast.Expression {
FILE: parser/import.go
method parseImport (line 8) | func (p *Parser) parseImport() ast.Expression {
FILE: parser/index.go
method parseIndexExpression (line 8) | func (p *Parser) parseIndexExpression(left ast.Expression) ast.Expression {
FILE: parser/integer.go
method parseIntegerLiteral (line 10) | func (p *Parser) parseIntegerLiteral() ast.Expression {
FILE: parser/null.go
method parseNull (line 7) | func (p *Parser) parseNull() ast.Expression {
FILE: parser/package.go
method parsePackage (line 8) | func (p *Parser) parsePackage() ast.Expression {
FILE: parser/parser.go
constant _ (line 12) | _ int = iota
constant LOWEST (line 13) | LOWEST
constant ASSIGN (line 14) | ASSIGN
constant COND (line 15) | COND
constant EQUALS (line 16) | EQUALS
constant LESSGREATER (line 17) | LESSGREATER
constant SUM (line 18) | SUM
constant PRODUCT (line 19) | PRODUCT
constant POWER (line 20) | POWER
constant MODULUS (line 21) | MODULUS
constant PREFIX (line 22) | PREFIX
constant CALL (line 23) | CALL
constant INDEX (line 24) | INDEX
constant DOT (line 25) | DOT
type prefixParseFn (line 57) | type prefixParseFn
type infixParseFn (line 58) | type infixParseFn
type postfixParseFn (line 59) | type postfixParseFn
type Parser (line 62) | type Parser struct
method registerPrefix (line 76) | func (p *Parser) registerPrefix(tokenType token.TokenType, fn prefixPa...
method registerInfix (line 80) | func (p *Parser) registerInfix(tokenType token.TokenType, fn infixPars...
method registerPostfix (line 84) | func (p *Parser) registerPostfix(tokenType token.TokenType, fn postfix...
method ParseProgram (line 150) | func (p *Parser) ParseProgram() *ast.Program {
method nextToken (line 165) | func (p *Parser) nextToken() {
method curTokenIs (line 171) | func (p *Parser) curTokenIs(t token.TokenType) bool {
method peekTokenIs (line 175) | func (p *Parser) peekTokenIs(t token.TokenType) bool {
method expectPeek (line 179) | func (p *Parser) expectPeek(t token.TokenType) bool {
method peekPrecedence (line 189) | func (p *Parser) peekPrecedence() int {
method curPrecedence (line 196) | func (p *Parser) curPrecedence() int {
method Errors (line 206) | func (p *Parser) Errors() []string {
method peekError (line 210) | func (p *Parser) peekError(t token.TokenType) {
method parseExpressionStatement (line 217) | func (p *Parser) parseExpressionStatement() *ast.ExpressionStatement {
method parseExpression (line 229) | func (p *Parser) parseExpression(precedence int) ast.Expression {
method parsePrefixExpression (line 257) | func (p *Parser) parsePrefixExpression() ast.Expression {
method noPrefixParseFnError (line 270) | func (p *Parser) noPrefixParseFnError(t token.TokenType) {
method parseInfixExpression (line 277) | func (p *Parser) parseInfixExpression(left ast.Expression) ast.Express...
method noInfixParseFnError (line 290) | func (p *Parser) noInfixParseFnError(t token.TokenType) {
method parseGroupedExpression (line 295) | func (p *Parser) parseGroupedExpression() ast.Expression {
method parsePostfixExpression (line 309) | func (p *Parser) parsePostfixExpression() ast.Expression {
function New (line 88) | func New(l *lexer.Lexer) *Parser {
FILE: parser/parser_test.go
function TestLetStatements (line 11) | func TestLetStatements(t *testing.T) {
function testLetStatement (line 45) | func testLetStatement(t *testing.T, s ast.Statement, name string) bool {
function checkParserErrors (line 69) | func checkParserErrors(t *testing.T, p *Parser) {
function TestReturnStatements (line 84) | func TestReturnStatements(t *testing.T) {
function TestIdentifierExpression (line 120) | func TestIdentifierExpression(t *testing.T) {
function TestIntergerLiteral (line 152) | func TestIntergerLiteral(t *testing.T) {
function TestParsingPrefixExpressions (line 183) | func TestParsingPrefixExpressions(t *testing.T) {
function testIntegerLiteral (line 225) | func testIntegerLiteral(t *testing.T, il ast.Expression, value int64) bo...
function TestParsingInfixExpressions (line 245) | func TestParsingInfixExpressions(t *testing.T) {
function TestOperatorPrecedenceParsing (line 290) | func TestOperatorPrecedenceParsing(t *testing.T) {
function testIdentifier (line 415) | func testIdentifier(t *testing.T, exp ast.Expression, value string) bool {
function testLiteralExpression (line 435) | func testLiteralExpression(
function testBooleanLiteral (line 455) | func testBooleanLiteral(t *testing.T, exp ast.Expression, value bool) bo...
function testInfixExpression (line 470) | func testInfixExpression(
function TestBooleanExpression (line 499) | func TestBooleanExpression(t *testing.T) {
function TestIfExpression (line 536) | func TestIfExpression(t *testing.T) {
function TestIfElseExpression (line 580) | func TestIfElseExpression(t *testing.T) {
function TestFunctionLiteralParsing (line 639) | func TestFunctionLiteralParsing(t *testing.T) {
function TestFunctionParameterParsing (line 680) | func TestFunctionParameterParsing(t *testing.T) {
function TestCallExpressionParsing (line 709) | func TestCallExpressionParsing(t *testing.T) {
function TestStringLiteralExpression (line 745) | func TestStringLiteralExpression(t *testing.T) {
function TestParsingArrayLiterals (line 764) | func TestParsingArrayLiterals(t *testing.T) {
function TestParsingIndexExpressions (line 783) | func TestParsingIndexExpressions(t *testing.T) {
function TestParsingDictLiteralsStringKeys (line 806) | func TestParsingDictLiteralsStringKeys(t *testing.T) {
function TestParsingDictLiteralsIntegerKeys (line 841) | func TestParsingDictLiteralsIntegerKeys(t *testing.T) {
function TestParsingDictLiteralsBoolKeys (line 876) | func TestParsingDictLiteralsBoolKeys(t *testing.T) {
function TestParsingDictLiteralWithExpressions (line 910) | func TestParsingDictLiteralWithExpressions(t *testing.T) {
function TestParsingEmptyDict (line 957) | func TestParsingEmptyDict(t *testing.T) {
function TestWhileLoop (line 976) | func TestWhileLoop(t *testing.T) {
function TestShorthandAssignment (line 1017) | func TestShorthandAssignment(t *testing.T) {
function TestForExpression (line 1035) | func TestForExpression(t *testing.T) {
function TestParsePostfix (line 1067) | func TestParsePostfix(t *testing.T) {
function TestParseDot (line 1081) | func TestParseDot(t *testing.T) {
function TestParseSwitch (line 1095) | func TestParseSwitch(t *testing.T) {
function TestParseImport (line 1116) | func TestParseImport(t *testing.T) {
FILE: parser/statements.go
method parseStatement (line 10) | func (p *Parser) parseStatement() ast.Statement {
method parseLetStatement (line 25) | func (p *Parser) parseLetStatement() *ast.LetStatement {
method parseReturnStatement (line 49) | func (p *Parser) parseReturnStatement() *ast.ReturnStatement {
method parseBlockStatement (line 62) | func (p *Parser) parseBlockStatement() *ast.BlockStatement {
FILE: parser/string.go
method parseStringLiteral (line 7) | func (p *Parser) parseStringLiteral() ast.Expression {
FILE: parser/switch.go
method parseSwitchStatement (line 10) | func (p *Parser) parseSwitchStatement() ast.Expression {
FILE: parser/while.go
method parseWhileExpression (line 8) | func (p *Parser) parseWhileExpression() ast.Expression {
FILE: repl/docs.go
type item (line 40) | type item struct
method Title (line 44) | func (i item) Title() string { return i.title }
method Description (line 45) | func (i item) Description() string { return i.desc }
method FilterValue (line 46) | func (i item) FilterValue() string { return i.title }
type languages (line 48) | type languages struct
method Title (line 52) | func (l languages) Title() string { return l.title }
method Description (line 53) | func (l languages) Description() string { return l.desc }
method FilterValue (line 54) | func (l languages) FilterValue() string { return l.title }
type playground (line 56) | type playground struct
method Init (line 75) | func (pg playground) Init() tea.Cmd {
method Update (line 79) | func (pg playground) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
method View (line 319) | func (pg playground) View() string {
FILE: repl/repl.go
constant PROMPT (line 22) | PROMPT = ">>> "
function Read (line 27) | func Read(contents string) {
function Start (line 52) | func Start() {
type dummy (line 67) | type dummy struct
method executor (line 71) | func (d *dummy) executor(in string) {
function completer (line 96) | func completer(in prompt.Document) []prompt.Suggest {
function Docs (line 100) | func Docs() {
FILE: token/token.go
type TokenType (line 5) | type TokenType
type Token (line 7) | type Token struct
constant ILLEGAL (line 14) | ILLEGAL = "HARAMU"
constant EOF (line 15) | EOF = "MWISHO"
constant IDENT (line 18) | IDENT = "KITAMBULISHI"
constant INT (line 19) | INT = "NAMBA"
constant STRING (line 20) | STRING = "NENO"
constant FLOAT (line 21) | FLOAT = "DESIMALI"
constant ASSIGN (line 24) | ASSIGN = "="
constant PLUS (line 25) | PLUS = "+"
constant MINUS (line 26) | MINUS = "-"
constant BANG (line 27) | BANG = "!"
constant ASTERISK (line 28) | ASTERISK = "*"
constant POW (line 29) | POW = "**"
constant SLASH (line 30) | SLASH = "/"
constant MODULUS (line 31) | MODULUS = "%"
constant LT (line 32) | LT = "<"
constant LTE (line 33) | LTE = "<="
constant GT (line 34) | GT = ">"
constant GTE (line 35) | GTE = ">="
constant EQ (line 36) | EQ = "=="
constant NOT_EQ (line 37) | NOT_EQ = "!="
constant AND (line 38) | AND = "&&"
constant OR (line 39) | OR = "||"
constant PLUS_ASSIGN (line 40) | PLUS_ASSIGN = "+="
constant PLUS_PLUS (line 41) | PLUS_PLUS = "++"
constant MINUS_ASSIGN (line 42) | MINUS_ASSIGN = "-="
constant MINUS_MINUS (line 43) | MINUS_MINUS = "--"
constant ASTERISK_ASSIGN (line 44) | ASTERISK_ASSIGN = "*="
constant SLASH_ASSIGN (line 45) | SLASH_ASSIGN = "/="
constant MODULUS_ASSIGN (line 46) | MODULUS_ASSIGN = "%="
constant SHEBANG (line 47) | SHEBANG = "#!"
constant COMMA (line 50) | COMMA = ","
constant SEMICOLON (line 51) | SEMICOLON = ";"
constant LPAREN (line 52) | LPAREN = "("
constant RPAREN (line 53) | RPAREN = ")"
constant LBRACE (line 54) | LBRACE = "{"
constant RBRACE (line 55) | RBRACE = "}"
constant LBRACKET (line 56) | LBRACKET = "["
constant RBRACKET (line 57) | RBRACKET = "]"
constant COLON (line 58) | COLON = ":"
constant DOT (line 59) | DOT = "."
constant AT (line 60) | AT = "@"
constant FUNCTION (line 63) | FUNCTION = "FUNCTION"
constant LET (line 64) | LET = "FANYA"
constant TRUE (line 65) | TRUE = "KWELI"
constant FALSE (line 66) | FALSE = "SIKWELI"
constant IF (line 67) | IF = "KAMA"
constant ELSE (line 68) | ELSE = "SIVYO"
constant RETURN (line 69) | RETURN = "RUDISHA"
constant WHILE (line 70) | WHILE = "WAKATI"
constant NULL (line 71) | NULL = "TUPU"
constant BREAK (line 72) | BREAK = "VUNJA"
constant CONTINUE (line 73) | CONTINUE = "ENDELEA"
constant IN (line 74) | IN = "KTK"
constant FOR (line 75) | FOR = "KWA"
constant SWITCH (line 76) | SWITCH = "BADILI"
constant CASE (line 77) | CASE = "IKIWA"
constant DEFAULT (line 78) | DEFAULT = "KAWAIDA"
constant IMPORT (line 79) | IMPORT = "TUMIA"
constant PACKAGE (line 80) | PACKAGE = "PAKEJI"
function LookupIdent (line 106) | func LookupIdent(ident string) TokenType {
Condensed preview — 166 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (452K chars).
[
{
"path": ".github/ISSUE_TEMPLATE/bug-report.yml",
"chars": 2412,
"preview": "name: 🐛 Bug Report\ndescription: Report a bug\ntitle: (bug report summary)\nlabels: Bug\nbody:\n - type: textarea\n id: de"
},
{
"path": ".github/ISSUE_TEMPLATE/feature-request.yml",
"chars": 1801,
"preview": "name: 🚀 Feature Request\ndescription: Suggest an idea for this project\ntitle: (feature request summary)\nlabels: Feature R"
},
{
"path": ".github/PULL_REQUEST_TEMPLATE",
"chars": 672,
"preview": "\n\n<!--\n\nPlease title your PR as follows: `module: description` (e.g. `time: fix date format`).\nAlways start with the thi"
},
{
"path": ".github/workflows/build.yml",
"chars": 572,
"preview": "name: Go\n\non:\n push:\n tags:\n - \"*\"\n\njobs:\n build:\n runs-on: ubuntu-latest\n steps:\n - uses: actions/ch"
},
{
"path": ".github/workflows/tests.yml",
"chars": 284,
"preview": "name: Go\n\non:\n push:\n branches: [ main, dev ]\n\njobs:\n\n build:\n runs-on: ubuntu-latest\n steps:\n - uses: act"
},
{
"path": ".gitignore",
"chars": 802,
"preview": ".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*."
},
{
"path": ".goreleaser.yaml",
"chars": 944,
"preview": "project_name: nuru\nbefore:\n hooks:\n - go mod tidy\n - go generate ./...\n\nbuilds:\n - env:\n - CGO_ENABLED=0\n "
},
{
"path": "ABOUT.md",
"chars": 4938,
"preview": "# NURU PROGRAMMING LANGUAGE\n\nThis page intends to show the origins of Nuru, its purpose, what it can be used for, what i"
},
{
"path": "LICENSE",
"chars": 18092,
"preview": " GNU GENERAL PUBLIC LICENSE\n Version 2, June 1991\n\n Copyright (C) 1989, 1991 Fr"
},
{
"path": "Makefile",
"chars": 1698,
"preview": "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 "
},
{
"path": "README.md",
"chars": 9783,
"preview": "<h1 align=\"center\">NURU🔥PROGRAMMING🔥LANGUAGE</h1>\n<p align=\"center\">\n <a href=\"https://github.com/NuruProgramming/Nur"
},
{
"path": "ast/ast.go",
"chars": 14933,
"preview": "package ast\n\nimport (\n\t\"bytes\"\n\t\"strings\"\n\n\t\"github.com/NuruProgramming/Nuru/token\"\n)\n\ntype Node interface {\n\tTokenLiter"
},
{
"path": "ast/ast_test.go",
"chars": 610,
"preview": "package ast\n\nimport (\n\t\"testing\"\n\n\t\"github.com/NuruProgramming/Nuru/token\"\n)\n\nfunc TestString(t *testing.T) {\n\tprogram :"
},
{
"path": "evaluator/assign.go",
"chars": 305,
"preview": "package evaluator\n\nimport (\n\t\"github.com/NuruProgramming/Nuru/ast\"\n\t\"github.com/NuruProgramming/Nuru/object\"\n)\n\nfunc eva"
},
{
"path": "evaluator/assignEqual.go",
"chars": 5405,
"preview": "package evaluator\n\nimport (\n\t\"strings\"\n\n\t\"github.com/NuruProgramming/Nuru/ast\"\n\t\"github.com/NuruProgramming/Nuru/object\""
},
{
"path": "evaluator/at.go",
"chars": 266,
"preview": "package evaluator\n\nimport (\n\t\"github.com/NuruProgramming/Nuru/ast\"\n\t\"github.com/NuruProgramming/Nuru/object\"\n)\n\nfunc eva"
},
{
"path": "evaluator/bang.go",
"chars": 263,
"preview": "package evaluator\n\nimport \"github.com/NuruProgramming/Nuru/object\"\n\nfunc evalBangOperatorExpression(right object.Object)"
},
{
"path": "evaluator/block.go",
"chars": 521,
"preview": "package evaluator\n\nimport (\n\t\"github.com/NuruProgramming/Nuru/ast\"\n\t\"github.com/NuruProgramming/Nuru/object\"\n)\n\nfunc eva"
},
{
"path": "evaluator/builtins.go",
"chars": 1740,
"preview": "//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/NuruProgrammi"
},
{
"path": "evaluator/builtins_common.go",
"chars": 5059,
"preview": "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 = m"
},
{
"path": "evaluator/builtins_wasm.go",
"chars": 1772,
"preview": "//go:build wasm && js\n\n// Modified version with of the builtins.go file with browser friendly versions of functions.\npac"
},
{
"path": "evaluator/call.go",
"chars": 2562,
"preview": "package evaluator\n\nimport (\n\t\"github.com/NuruProgramming/Nuru/ast\"\n\t\"github.com/NuruProgramming/Nuru/object\"\n)\n\nfunc eva"
},
{
"path": "evaluator/dict.go",
"chars": 709,
"preview": "package evaluator\n\nimport (\n\t\"github.com/NuruProgramming/Nuru/ast\"\n\t\"github.com/NuruProgramming/Nuru/object\"\n)\n\nfunc eva"
},
{
"path": "evaluator/error_handler.go",
"chars": 204,
"preview": "package evaluator\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/NuruProgramming/Nuru/object\"\n)\n\nfunc newError(format string, a ...inter"
},
{
"path": "evaluator/evaluator.go",
"chars": 9145,
"preview": "package evaluator\n\nimport (\n\t\"github.com/NuruProgramming/Nuru/ast\"\n\t\"github.com/NuruProgramming/Nuru/object\"\n)\n\nvar (\n\tN"
},
{
"path": "evaluator/evaluator_test.go",
"chars": 21103,
"preview": "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/NuruProgram"
},
{
"path": "evaluator/forin.go",
"chars": 756,
"preview": "package evaluator\n\nimport (\n\t\"github.com/NuruProgramming/Nuru/ast\"\n\t\"github.com/NuruProgramming/Nuru/object\"\n)\n\nfunc eva"
},
{
"path": "evaluator/function.go",
"chars": 381,
"preview": "package evaluator\n\nimport (\n\t\"github.com/NuruProgramming/Nuru/ast\"\n\t\"github.com/NuruProgramming/Nuru/object\"\n)\n\nfunc eva"
},
{
"path": "evaluator/identifier.go",
"chars": 403,
"preview": "package evaluator\n\nimport (\n\t\"github.com/NuruProgramming/Nuru/ast\"\n\t\"github.com/NuruProgramming/Nuru/object\"\n)\n\nfunc eva"
},
{
"path": "evaluator/if.go",
"chars": 444,
"preview": "package evaluator\n\nimport (\n\t\"github.com/NuruProgramming/Nuru/ast\"\n\t\"github.com/NuruProgramming/Nuru/object\"\n)\n\nfunc eva"
},
{
"path": "evaluator/import.go",
"chars": 2151,
"preview": "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.co"
},
{
"path": "evaluator/in.go",
"chars": 1935,
"preview": "package evaluator\n\nimport (\n\t\"strings\"\n\n\t\"github.com/NuruProgramming/Nuru/object\"\n)\n\nfunc evalInExpression(left, right o"
},
{
"path": "evaluator/index.go",
"chars": 1261,
"preview": "package evaluator\n\nimport \"github.com/NuruProgramming/Nuru/object\"\n\nfunc evalIndexExpression(left, index object.Object, "
},
{
"path": "evaluator/infix.go",
"chars": 8146,
"preview": "package evaluator\n\nimport (\n\t\"math\"\n\t\"strings\"\n\n\t\"github.com/NuruProgramming/Nuru/object\"\n)\n\nfunc evalInfixExpression(op"
},
{
"path": "evaluator/method.go",
"chars": 3231,
"preview": "package evaluator\n\nimport (\n\t\"github.com/NuruProgramming/Nuru/ast\"\n\t\"github.com/NuruProgramming/Nuru/object\"\n)\n\nfunc eva"
},
{
"path": "evaluator/package.go",
"chars": 383,
"preview": "package evaluator\n\nimport (\n\t\"github.com/NuruProgramming/Nuru/ast\"\n\t\"github.com/NuruProgramming/Nuru/object\"\n)\n\nfunc eva"
},
{
"path": "evaluator/postfix.go",
"chars": 1350,
"preview": "package evaluator\n\nimport (\n\t\"github.com/NuruProgramming/Nuru/ast\"\n\t\"github.com/NuruProgramming/Nuru/object\"\n)\n\nfunc eva"
},
{
"path": "evaluator/prefix.go",
"chars": 1153,
"preview": "package evaluator\n\nimport \"github.com/NuruProgramming/Nuru/object\"\n\nfunc evalMinusPrefixOperatorExpression(right object."
},
{
"path": "evaluator/property.go",
"chars": 1673,
"preview": "package evaluator\n\nimport (\n\t\"github.com/NuruProgramming/Nuru/ast\"\n\t\"github.com/NuruProgramming/Nuru/object\"\n)\n\nfunc eva"
},
{
"path": "evaluator/switch.go",
"chars": 643,
"preview": "package evaluator\n\nimport (\n\t\"github.com/NuruProgramming/Nuru/ast\"\n\t\"github.com/NuruProgramming/Nuru/object\"\n)\n\nfunc eva"
},
{
"path": "evaluator/type.go",
"chars": 1808,
"preview": "package evaluator\n\nimport (\n\t\"strconv\"\n\n\t\"github.com/NuruProgramming/Nuru/object\"\n)\n\nfunc convertToInteger(obj object.Ob"
},
{
"path": "evaluator/while.go",
"chars": 740,
"preview": "package evaluator\n\nimport (\n\t\"github.com/NuruProgramming/Nuru/ast\"\n\t\"github.com/NuruProgramming/Nuru/object\"\n)\n\nconst MA"
},
{
"path": "examples/Astart.nr",
"chars": 4332,
"preview": "/*############ A*(A-star) Algorithm ##############\n \n By @VictorKariuki\n\n https://github."
},
{
"path": "examples/example.nr",
"chars": 5581,
"preview": "// basics\n\njina = \"Nuru\"\nandika(jina) // Nuru\n\n// lists\n\norodha = [1, \"pili\", kweli]\n\nnamba = [10, 20, 30]\njina = namba["
},
{
"path": "examples/perceptron.nr",
"chars": 5220,
"preview": "tumia hisabati\n\n// Mbinu za Kupanga\n//orodhesha(kwanza, mwisho, umbali), huunda orodha ya nambari na umbali uliowekwa ka"
},
{
"path": "examples/reduce.nr",
"chars": 696,
"preview": "fanya reduce = unda(iterator, callback, initialValue) {\n fanya accumulator = initialValue;\n\n kwa thamani ktk iterator "
},
{
"path": "examples/sarufi.nr",
"chars": 1031,
"preview": "tumia mtandao\ntumia jsoni\npakeji sarufi {\n andaa = unda(file) {\n config = fungua(file)\n configString = "
},
{
"path": "examples/sorting_algorithm.nr",
"chars": 1397,
"preview": "/* \n############ Sorting Algorithm ##############\n \n By @VictorKariuki\n\n https://github.c"
},
{
"path": "examples/sudoku_solver.nr",
"chars": 2639,
"preview": "/*########### Backtracking Algorithm ##############\n \n By @VictorKariuki\n\n https://gith"
},
{
"path": "extensions/README.md",
"chars": 434,
"preview": "# Nuru Extensions For Various Editors\n\n## [VSCODE](./vscode/)\n\nNuru syntax highlighting on VSCode\n\n## [VIM](./vim)\n\nThe "
},
{
"path": "extensions/vim/syntax/nuru.vim",
"chars": 1525,
"preview": "\" Sintaksia ya nuru kwenye programu ya \"vim\"\n\" Lugha: Nuru\n\n\" Maneno tengwa\nsyntax keyword nuruKeyword unda pakeji rudis"
},
{
"path": "extensions/vscode/CHANGELOG.md",
"chars": 231,
"preview": "# Change Log\n\nAll notable changes to the \"nuru\" extension will be documented in this file.\n\nCheck [Keep a Changelog](htt"
},
{
"path": "extensions/vscode/README.md",
"chars": 789,
"preview": "# Nuru VSCode Extension\n\nThis is a syntax highliting extension for Nuru on vscode. It detects `.nr` and `.sw` files.\n\n##"
},
{
"path": "go.mod",
"chars": 1791,
"preview": "module github.com/NuruProgramming/Nuru\n\ngo 1.18\n\nrequire (\n\tgithub.com/AvicennaJr/GoPrompt v0.0.0-20230411215003-be2316d"
},
{
"path": "go.sum",
"chars": 11589,
"preview": "github.com/AvicennaJr/GoPrompt v0.0.0-20230411215003-be2316d88e2d h1:H+Y1MQQXd83x0xC2MPOw+gFFozKTXgcW69bV80+/wpY=\ngithub"
},
{
"path": "lexer/lexer.go",
"chars": 8036,
"preview": "// This will convert the sequence of characters into a sequence of tokens\n\npackage lexer\n\nimport (\n\t\"github.com/NuruProg"
},
{
"path": "lexer/lexer_test.go",
"chars": 3881,
"preview": "package lexer\n\nimport (\n\t\"testing\"\n\n\t\"github.com/NuruProgramming/Nuru/token\"\n)\n\nfunc TestNextToken(t *testing.T) {\n\tinpu"
},
{
"path": "main.go",
"chars": 2094,
"preview": "//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\"githu"
},
{
"path": "main_wasm.go",
"chars": 1122,
"preview": "//go:build wasm && js\n\npackage main\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/NuruProgramming/Nuru/evaluator\"\n\t\"github.com/NuruProg"
},
{
"path": "module/hisabati.go",
"chars": 21650,
"preview": "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 = "
},
{
"path": "module/json.go",
"chars": 2684,
"preview": "package module\n\nimport (\n\t\"encoding/json\"\n\n\t\"github.com/NuruProgramming/Nuru/object\"\n)\n\nvar JsonFunctions = map[string]o"
},
{
"path": "module/module.go",
"chars": 492,
"preview": "package module\n\nimport \"github.com/NuruProgramming/Nuru/object\"\n\nvar Mapper = map[string]*object.Module{}\n\nfunc init() {"
},
{
"path": "module/net.go",
"chars": 4910,
"preview": "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)"
},
{
"path": "module/os.go",
"chars": 1127,
"preview": "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"
},
{
"path": "module/time.go",
"chars": 4933,
"preview": "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"
},
{
"path": "object/array.go",
"chars": 2702,
"preview": "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)"
},
{
"path": "object/at.go",
"chars": 208,
"preview": "package object\n\nimport \"fmt\"\n\ntype At struct {\n\tInstance *Instance\n}\n\nfunc (a *At) Type() ObjectType { return AT }\nfunc "
},
{
"path": "object/bool.go",
"chars": 372,
"preview": "package object\n\ntype Boolean struct {\n\tValue bool\n}\n\nfunc (b *Boolean) Inspect() string {\n\tif b.Value {\n\t\treturn \"kweli\""
},
{
"path": "object/break.go",
"chars": 145,
"preview": "package object\n\ntype Break struct{}\n\nfunc (b *Break) Type() ObjectType { return BREAK_OBJ }\nfunc (b *Break) Inspect() st"
},
{
"path": "object/builtin.go",
"chars": 236,
"preview": "package object\n\ntype BuiltinFunction func(args ...Object) Object\n\ntype Builtin struct {\n\tFn BuiltinFunction\n}\n\nfunc (b *"
},
{
"path": "object/byte.go",
"chars": 180,
"preview": "package object\n\ntype Byte struct {\n\tValue []byte\n\tString string\n}\n\nfunc (b *Byte) Inspect() string { return \"b\" + b.St"
},
{
"path": "object/continue.go",
"chars": 160,
"preview": "package object\n\ntype Continue struct{}\n\nfunc (c *Continue) Type() ObjectType { return CONTINUE_OBJ }\nfunc (c *Continue) "
},
{
"path": "object/dict.go",
"chars": 958,
"preview": "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\ntyp"
},
{
"path": "object/environment.go",
"chars": 705,
"preview": "package object\n\nfunc NewEnclosedEnvironment(outer *Environment) *Environment {\n\tenv := NewEnvironment()\n\tenv.outer = out"
},
{
"path": "object/error.go",
"chars": 264,
"preview": "//go:build !js || !wasm\npackage object\n\nimport \"fmt\"\n\ntype Error struct {\n\tMessage string\n}\n\nfunc (e *Error) Inspect() s"
},
{
"path": "object/error_wasm.go",
"chars": 278,
"preview": "//go:build wasm && js\npackage object\n\ntype Error struct {\n\tMessage string\n}\n\nfunc (e *Error) Inspect() string {\n\t// msg "
},
{
"path": "object/file.go",
"chars": 1668,
"preview": "package object\n\nimport (\n\t\"os\"\n)\n\ntype File struct {\n\tFilename string\n\tContent string\n}\n\nfunc (f *File) Type() ObjectTy"
},
{
"path": "object/float.go",
"chars": 369,
"preview": "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() strin"
},
{
"path": "object/function.go",
"chars": 678,
"preview": "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 "
},
{
"path": "object/instance.go",
"chars": 249,
"preview": "package object\n\nimport \"fmt\"\n\ntype Instance struct {\n\tPackage *Package\n\tEnv *Environment\n}\n\nfunc (i *Instance) Type("
},
{
"path": "object/integer.go",
"chars": 298,
"preview": "package object\n\nimport \"fmt\"\n\ntype Integer struct {\n\tValue int64\n}\n\nfunc (i *Integer) Inspect() string { return fmt.Spr"
},
{
"path": "object/module.go",
"chars": 385,
"preview": "package object\n\ntype ModuleFunction func(args []Object, defs map[string]Object) Object\n\ntype Module struct {\n\tName "
},
{
"path": "object/null.go",
"chars": 140,
"preview": "package object\n\ntype Null struct{}\n\nfunc (n *Null) Inspect() string { return \"null\" }\nfunc (n *Null) Type() ObjectType "
},
{
"path": "object/object.go",
"chars": 1124,
"preview": "package object\n\nimport (\n\t\"fmt\"\n)\n\ntype ObjectType string\n\nconst (\n\tINTEGER_OBJ = \"NAMBA\"\n\tFLOAT_OBJ = \"DESI"
},
{
"path": "object/object_test.go",
"chars": 586,
"preview": "package object\n\nimport \"testing\"\n\nfunc TestStringHashKey(t *testing.T) {\n\thello1 := &String{Value: \"Hello World\"}\n\thello"
},
{
"path": "object/package.go",
"chars": 309,
"preview": "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"
},
{
"path": "object/return.go",
"chars": 199,
"preview": "package object\n\ntype ReturnValue struct {\n\tValue Object\n}\n\nfunc (rv *ReturnValue) Inspect() string { return rv.Value.In"
},
{
"path": "object/strings.go",
"chars": 3794,
"preview": "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\n"
},
{
"path": "object/time.go",
"chars": 2536,
"preview": "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() Obje"
},
{
"path": "parser/arrays.go",
"chars": 688,
"preview": "package parser\n\nimport (\n\t\"github.com/NuruProgramming/Nuru/ast\"\n\t\"github.com/NuruProgramming/Nuru/token\"\n)\n\nfunc (p *Par"
},
{
"path": "parser/assignEqual.go",
"chars": 900,
"preview": "package parser\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/NuruProgramming/Nuru/ast\"\n)\n\nfunc (p *Parser) parseAssignEqualExpression(e"
},
{
"path": "parser/assignment.go",
"chars": 1123,
"preview": "package parser\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/NuruProgramming/Nuru/ast\"\n)\n\nfunc (p *Parser) parseAssignmentExpression(ex"
},
{
"path": "parser/at.go",
"chars": 143,
"preview": "package parser\n\nimport \"github.com/NuruProgramming/Nuru/ast\"\n\nfunc (p *Parser) parseAt() ast.Expression {\n\treturn &ast.A"
},
{
"path": "parser/boolean.go",
"chars": 232,
"preview": "package parser\n\nimport (\n\t\"github.com/NuruProgramming/Nuru/ast\"\n\t\"github.com/NuruProgramming/Nuru/token\"\n)\n\nfunc (p *Par"
},
{
"path": "parser/break.go",
"chars": 261,
"preview": "package parser\n\nimport (\n\t\"github.com/NuruProgramming/Nuru/ast\"\n\t\"github.com/NuruProgramming/Nuru/token\"\n)\n\nfunc (p *Par"
},
{
"path": "parser/continue.go",
"chars": 270,
"preview": "package parser\n\nimport (\n\t\"github.com/NuruProgramming/Nuru/ast\"\n\t\"github.com/NuruProgramming/Nuru/token\"\n)\n\nfunc (p *Par"
},
{
"path": "parser/dict.go",
"chars": 637,
"preview": "package parser\n\nimport (\n\t\"github.com/NuruProgramming/Nuru/ast\"\n\t\"github.com/NuruProgramming/Nuru/token\"\n)\n\nfunc (p *Par"
},
{
"path": "parser/dot.go",
"chars": 1036,
"preview": "package parser\n\nimport (\n\t\"github.com/NuruProgramming/Nuru/ast\"\n\t\"github.com/NuruProgramming/Nuru/token\"\n)\n\nfunc (p *Par"
},
{
"path": "parser/float.go",
"chars": 447,
"preview": "package parser\n\nimport (\n\t\"fmt\"\n\t\"strconv\"\n\n\t\"github.com/NuruProgramming/Nuru/ast\"\n)\n\nfunc (p *Parser) parseFloatLiteral"
},
{
"path": "parser/for.go",
"chars": 2149,
"preview": "package parser\n\nimport (\n\t\"github.com/NuruProgramming/Nuru/ast\"\n\t\"github.com/NuruProgramming/Nuru/token\"\n)\n\nfunc (p *Par"
},
{
"path": "parser/function.go",
"chars": 1393,
"preview": "package parser\n\nimport (\n\t\"github.com/NuruProgramming/Nuru/ast\"\n\t\"github.com/NuruProgramming/Nuru/token\"\n)\n\nfunc (p *Par"
},
{
"path": "parser/identifier.go",
"chars": 191,
"preview": "package parser\n\nimport (\n\t\"github.com/NuruProgramming/Nuru/ast\"\n)\n\nfunc (p *Parser) parseIdentifier() ast.Expression {\n\t"
},
{
"path": "parser/if.go",
"chars": 911,
"preview": "package parser\n\nimport (\n\t\"github.com/NuruProgramming/Nuru/ast\"\n\t\"github.com/NuruProgramming/Nuru/token\"\n)\n\nfunc (p *Par"
},
{
"path": "parser/import.go",
"chars": 534,
"preview": "package parser\n\nimport (\n\t\"github.com/NuruProgramming/Nuru/ast\"\n\t\"github.com/NuruProgramming/Nuru/token\"\n)\n\nfunc (p *Par"
},
{
"path": "parser/index.go",
"chars": 366,
"preview": "package parser\n\nimport (\n\t\"github.com/NuruProgramming/Nuru/ast\"\n\t\"github.com/NuruProgramming/Nuru/token\"\n)\n\nfunc (p *Par"
},
{
"path": "parser/integer.go",
"chars": 454,
"preview": "package parser\n\nimport (\n\t\"fmt\"\n\t\"strconv\"\n\n\t\"github.com/NuruProgramming/Nuru/ast\"\n)\n\nfunc (p *Parser) parseIntegerLiter"
},
{
"path": "parser/null.go",
"chars": 152,
"preview": "package parser\n\nimport (\n\t\"github.com/NuruProgramming/Nuru/ast\"\n)\n\nfunc (p *Parser) parseNull() ast.Expression {\n\treturn"
},
{
"path": "parser/package.go",
"chars": 416,
"preview": "package parser\n\nimport (\n\t\"github.com/NuruProgramming/Nuru/ast\"\n\t\"github.com/NuruProgramming/Nuru/token\"\n)\n\nfunc (p *Par"
},
{
"path": "parser/parser.go",
"chars": 8360,
"preview": "package parser\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/NuruProgramming/Nuru/ast\"\n\t\"github.com/NuruProgramming/Nuru/lexer\"\n\t\"githu"
},
{
"path": "parser/parser_test.go",
"chars": 25357,
"preview": "package parser\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/NuruProgramming/Nuru/ast\"\n\t\"github.com/NuruProgramming/Nuru/lex"
},
{
"path": "parser/statements.go",
"chars": 1575,
"preview": "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"
},
{
"path": "parser/string.go",
"chars": 197,
"preview": "package parser\n\nimport (\n\t\"github.com/NuruProgramming/Nuru/ast\"\n)\n\nfunc (p *Parser) parseStringLiteral() ast.Expression "
},
{
"path": "parser/switch.go",
"chars": 1813,
"preview": "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"
},
{
"path": "parser/while.go",
"chars": 512,
"preview": "package parser\n\nimport (\n\t\"github.com/NuruProgramming/Nuru/ast\"\n\t\"github.com/NuruProgramming/Nuru/token\"\n)\n\nfunc (p *Par"
},
{
"path": "repl/docs/en/README.md",
"chars": 6907,
"preview": "# NURU PROGRAMMING LANGUAGE DOCUMENTATION\n\nThis documentation is intended for people with some experience in programming"
},
{
"path": "repl/docs/en/arrays.md",
"chars": 2797,
"preview": "# Arrays in Nuru\n\nArrays in Nuru are versatile data structures that can hold multiple items, including different types s"
},
{
"path": "repl/docs/en/bool.md",
"chars": 2534,
"preview": "# Working with Booleans in Nuru\n\nBoolean objects in Nuru are truthy, meaning that any value is true, except tupu and sik"
},
{
"path": "repl/docs/en/builtins.md",
"chars": 1632,
"preview": "# Built-in Functions in Nuru\n\nNuru has several built-in functions that perform specific tasks.\n\n## The andika() Function"
},
{
"path": "repl/docs/en/comments.md",
"chars": 1539,
"preview": "# Comments in Nuru\n\nIn Nuru, you can write comments to provide explanations and documentation for your code. Comments ar"
},
{
"path": "repl/docs/en/dictionaries.md",
"chars": 2250,
"preview": "# Dictionaries in Nuru\n\nDictionaries in Nuru, also known as \"kamusi,\" are powerful and flexible data structures that sto"
},
{
"path": "repl/docs/en/files.md",
"chars": 511,
"preview": "# 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"
},
{
"path": "repl/docs/en/for.md",
"chars": 2325,
"preview": "# For Loops in Nuru\n\nFor loops are a fundamental control structure in Nuru, used for iterating over iterable objects suc"
},
{
"path": "repl/docs/en/function.md",
"chars": 2355,
"preview": "# Functions in Nuru\n\nFunctions are a fundamental part of Nuru programming, allowing you to define reusable blocks of cod"
},
{
"path": "repl/docs/en/hisabati.md",
"chars": 7198,
"preview": "# Module Hisabati\n\nModule Hisabati is a inbuilt math module by [VictorKariuki](https://github.com/VictorKariuki).\n\nThis "
},
{
"path": "repl/docs/en/identifiers.md",
"chars": 1347,
"preview": "# Identifiers in Nuru\n\nIdentifiers are used to name variables, functions, and other elements in your Nuru code. This pag"
},
{
"path": "repl/docs/en/ifStatements.md",
"chars": 1428,
"preview": "# Conditional Statements in Nuru\n\nConditional statements in Nuru are used to perform different actions based on differen"
},
{
"path": "repl/docs/en/json.md",
"chars": 1185,
"preview": "# 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"
},
{
"path": "repl/docs/en/keywords.md",
"chars": 1584,
"preview": "# KEYWORDS\n\nKeywords in Nuru are reserved words that have special meanings and cannot be used as identifiers for variabl"
},
{
"path": "repl/docs/en/net.md",
"chars": 966,
"preview": "# HTTP with Nuru\n\nYou can access the internet via http protocol using the `mtandao` module.\n\n## Importing\n\nImport the mo"
},
{
"path": "repl/docs/en/null.md",
"chars": 777,
"preview": "# Null (Tupu) in Nuru\n\nThe null data type in Nuru represents the absence of a value or the concept of \"nothing\" or \"empt"
},
{
"path": "repl/docs/en/numbers.md",
"chars": 1189,
"preview": "# INTEGERS (NAMBA) AND FLOATS (DESIMALI)\n\nIntegers and floats are the basic numeric data types in Nuru, used for represe"
},
{
"path": "repl/docs/en/operators.md",
"chars": 2507,
"preview": "# OPERATORS\nOperators are the foundation of any programming language, allowing you to perform various operations on vari"
},
{
"path": "repl/docs/en/packages.md",
"chars": 2543,
"preview": "# Packages in Nuru\n\nYou can use third packages written in Nuru with the following conditions:\n\n- The package file MUST b"
},
{
"path": "repl/docs/en/range.md",
"chars": 1198,
"preview": "## Range Function (mfululizo)\n\nThe `mfululizo` function generates a sequence of numbers. It can be used in loops or to c"
},
{
"path": "repl/docs/en/strings.md",
"chars": 2265,
"preview": "# Strings in Nuru\n\nStrings are a sequence of characters that can represent text in the Nuru programming language. This p"
},
{
"path": "repl/docs/en/switch.md",
"chars": 1363,
"preview": "# Switch Statements in Nuru\n\nSwitch statements in Nuru allow you to execute different code blocks based on the value of "
},
{
"path": "repl/docs/en/time.md",
"chars": 1531,
"preview": "# 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\ntu"
},
{
"path": "repl/docs/en/while.md",
"chars": 1213,
"preview": "# WHILE (WAKATI)\n\nWhile loops in Nuru are used to execute a block of code repeatedly, as long as a given condition is tr"
},
{
"path": "repl/docs/sw/README.md",
"chars": 1557,
"preview": "# NYARAKA YA LUGHA YA PROGRAMU YA NURU\n\nHii nyaraka imeandikwa ikilenga watu wenye uzoefu na kuandika au kupanga program"
},
{
"path": "repl/docs/sw/arrays.md",
"chars": 2588,
"preview": "# Orodha Au Safu Katika Nuru\n\nSafu katika nuru ni miundo ya data ambayo inaweza kubeba vitu vingi, ikiwa ni pamoja na ai"
},
{
"path": "repl/docs/sw/bools.md",
"chars": 2658,
"preview": "# Kufanya Kazi na Buliani Katika Nuru\n\nVitu vyote katika Nuru ni kweli, yaani thamani yoyote ni kweli isipokua tupu and "
},
{
"path": "repl/docs/sw/builtins.md",
"chars": 1737,
"preview": "# Vitendakazi Vilivyojengwa Ndani ya Nuru\n\nNuru ina vitendakazi kadhaa vilivyojengwa ndani vinavyofanya kazi husika.\n\n##"
},
{
"path": "repl/docs/sw/dictionaries.md",
"chars": 2789,
"preview": "# Kamusi Katika Nuru\n\nKamusi katika Nuru ni miundo ya data inayotunza jozi za funguo-thamani. Ukurasa huu unatoa maelezo"
},
{
"path": "repl/docs/sw/for.md",
"chars": 2301,
"preview": "# Vitanzi Vya Kwa Katika Nuru\n\nVitanzi vya `kwa` ni muundo msingi wa udhibiti katika Nuru ambavyo hutumika kuzunguka vit"
},
{
"path": "repl/docs/sw/functions.md",
"chars": 2482,
"preview": "# Undo (Functions)\n\nVitendakazi ni sehemu ya msingi ya Nuru inayokuwezesha kuainisha mapande ya msimbo yanayoweza kutumi"
},
{
"path": "repl/docs/sw/identifiers.md",
"chars": 1519,
"preview": "# Vitambulisho katika Nuru\n\nVitambulisho hutumika kuweka majina kwenye vigezo, vitendakazi na vipengele vingine katika m"
},
{
"path": "repl/docs/sw/if.md",
"chars": 22,
"preview": "# Kama/Sivyo (If/Else)"
},
{
"path": "repl/docs/sw/keywords.md",
"chars": 26,
"preview": "# Maneno Muhimu (Keywords)"
},
{
"path": "repl/docs/sw/maoni.md",
"chars": 1462,
"preview": "# Maoni Katika Nuru\n\nKatika Nuru, unaweza kuandika maoni kutoa maelezo na hati kwa kazi yako. Maoni ni mistari ya maandi"
},
{
"path": "repl/docs/sw/null.md",
"chars": 13,
"preview": "# Tupu (Null)"
},
{
"path": "repl/docs/sw/numbers.md",
"chars": 33,
"preview": "# Namba na Desimali (Ints/Floats)"
},
{
"path": "repl/docs/sw/operators.md",
"chars": 23,
"preview": "# Matendaji (Operators)"
},
{
"path": "repl/docs/sw/range.md",
"chars": 1307,
"preview": "## Kitendakazi cha Mfululizo\n\nKitendakazi cha `mfululizo` hutoa mfululizo wa nambari, sawa na kitendakazi cha `range()` "
},
{
"path": "repl/docs/sw/strings.md",
"chars": 16,
"preview": "# Neno (Strings)"
},
{
"path": "repl/docs/sw/switch.md",
"chars": 17,
"preview": "# Badili (Switch)"
},
{
"path": "repl/docs/sw/while.md",
"chars": 16,
"preview": "# Wakati (While)"
},
{
"path": "repl/docs.go",
"chars": 9496,
"preview": "package repl\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/NuruProgramming/Nuru/evaluator\"\n\t\"github.com/NuruProgramming/Nuru"
},
{
"path": "repl/repl.go",
"chars": 6823,
"preview": "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/Nu"
},
{
"path": "sh/install.sh",
"chars": 4082,
"preview": "#!/usr/bin/env sh\n\n# Hii ni skripti ya shell ili kusakinisha programu ya Nuru.\n# Programu zinazohitajika:\n# - curl/wge"
},
{
"path": "styles/styles.go",
"chars": 599,
"preview": "package styles\n\nimport \"github.com/charmbracelet/lipgloss\"\n\nvar (\n\tTitleStyle = lipgloss.NewStyle().Margin(1, 0).Foreg"
},
{
"path": "third_party/math/README.md",
"chars": 9219,
"preview": "# Pakeji Hesabu (Math Package)\n\nPakeji Hesabu is a math package written in pure Nuru by [VictorKariuki](https://github.c"
},
{
"path": "third_party/math/hesabu.nr",
"chars": 14094,
"preview": "tumia hisabati\n\npakeji hesabu{\n //CONSTRUCTOR METHOD \n andaa = unda() {}\n\n // Constants\n // π (Pi)\n PI"
},
{
"path": "third_party/math/test.nr",
"chars": 1449,
"preview": "tumia \"hesabu\"\n\nandika(\"abs: \",hesabu.abs(-42));\nandika(\"acos: \",hesabu.acos(0.5));\nandika(\"acosh: \",hesabu.acosh(2));\na"
},
{
"path": "token/token.go",
"chars": 2001,
"preview": "// This is where we define our tokens\n\npackage token\n\ntype TokenType string\n\ntype Token struct {\n\tType TokenType\n\tLit"
}
]
// ... and 2 more files (download for full content)
About this extraction
This page contains the full source code of the AvicennaJr/Nuru GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 166 files (399.8 KB), approximately 125.8k tokens, and a symbol index with 654 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.