├── .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
├── assets
├── Nuru.png
├── Nuru.svg
└── nuru-logo (Transparent).png
├── ast
├── ast.go
└── ast_test.go
├── evaluator
├── assign.go
├── assignEqual.go
├── at.go
├── bang.go
├── block.go
├── builtins.go
├── call.go
├── dict.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
│ ├── assets
│ └── screenshot.png
│ └── nuru
│ ├── language-configuration.json
│ ├── package.json
│ └── syntaxes
│ └── nuru.tmLanguage.json
├── go.mod
├── go.sum
├── gotest
├── lexer
├── lexer.go
└── lexer_test.go
├── main.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
├── 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.go
├── 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
└── repl.go
├── styles
└── styles.go
├── third_party
└── math
│ ├── README.md
│ ├── hesabu.nr
│ └── test.nr
├── token
└── token.go
└── upx
/.github/ISSUE_TEMPLATE/bug-report.yml:
--------------------------------------------------------------------------------
1 | name: 🐛 Bug Report
2 | description: Report a bug
3 | title: (bug report summary)
4 | labels: Bug
5 | body:
6 | - type: textarea
7 | id: description
8 | attributes:
9 | label: Describe the bug
10 | description: What is the problem? A clear and concise description of the bug.
11 | validations:
12 | required: true
13 |
14 | - type: textarea
15 | id: expected
16 | attributes:
17 | label: Expected Behavior
18 | description: What did you expect to happen?
19 | validations:
20 | required: true
21 |
22 | - type: textarea
23 | id: current
24 | attributes:
25 | label: Current Behavior
26 | description: |
27 | What actually happened?
28 |
29 | Please include full errors, uncaught exceptions, stack traces, and relevant logs.
30 | If service/functions responses are relevant, please include wire logs.
31 | validations:
32 | required: true
33 |
34 | - type: textarea
35 | id: reproduction
36 | attributes:
37 | label: Reproduction Steps
38 | description: |
39 | Provide a self-contained, concise snippet of code that can be used to reproduce the issue.
40 | For more complex issues provide a repo with the smallest sample that reproduces the bug.
41 |
42 | Avoid including business logic or unrelated code, it makes diagnosis more difficult.
43 | The code sample should be an SSCCE. See http://sscce.org/ for details.
44 | In short, please provide a code sample that we can copy/paste, run and reproduce.
45 | validations:
46 | required: true
47 |
48 | - type: textarea
49 | id: solution
50 | attributes:
51 | label: Possible Solution
52 | description: Suggest a fix/reason for the bug
53 | validations:
54 | required: false
55 |
56 | - type: textarea
57 | id: context
58 | attributes:
59 | label: Additional Information/Context
60 | description: |
61 | Anything else that might be relevant for troubleshooting this bug.
62 | Providing context helps us come up with a solution that is most useful in the real world.
63 | validations:
64 | required: false
65 |
66 | - type: input
67 | id: version
68 | attributes:
69 | label: Nuru version
70 | description: |
71 | Please make sure to use the latest version of Nuru before reporting any issues as it may have already been fixed.
72 | validations:
73 | required: true
74 |
75 | - type: textarea
76 | id: environment
77 | attributes:
78 | label: Environment details (OS name and version, etc.)
79 | description: Your operating system (Windows, Linux, Android or MacOS)
80 | validations:
81 | required: true
82 |
83 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature-request.yml:
--------------------------------------------------------------------------------
1 | name: 🚀 Feature Request
2 | description: Suggest an idea for this project
3 | title: (feature request summary)
4 | labels: Feature Request
5 | body:
6 | - type: textarea
7 | id: description
8 | attributes:
9 | label: Describe the feature
10 | description: A clear and concise description of the feature you are proposing.
11 | validations:
12 | required: true
13 |
14 | - type: textarea
15 | id: use-case
16 | attributes:
17 | label: Use Case
18 | description: |
19 | Why do you need this feature? For example: "I'm always frustrated when..."
20 | validations:
21 | required: true
22 |
23 | - type: textarea
24 | id: solution
25 | attributes:
26 | label: Proposed Solution
27 | description: Suggest how to implement the addition or change. Please include prototype/workaround/sketch/reference implementation.
28 | validations:
29 | required: false
30 |
31 | - type: textarea
32 | id: other
33 | attributes:
34 | label: Other Information
35 | description: Any alternative solutions or features you considered, a more detailed explanation, stack traces, related issues, links for context, etc.
36 | validations:
37 | required: false
38 |
39 | - type: checkboxes
40 | id: ack
41 | attributes:
42 | label: Acknowledgements
43 | options:
44 | - label: I may be able to implement this feature request
45 | required: false
46 |
47 | - label: This feature might incur a breaking change
48 | required: false
49 |
50 | - type: input
51 | id: version
52 | attributes:
53 | label: Version used
54 | description: Please provide the version of the repository or tool you are using.
55 | validations:
56 | required: true
57 |
58 | - type: textarea
59 | id: environment
60 | attributes:
61 | label: Environment details (OS name and version, etc.)
62 | description: Your operating system (Linux, Windows, Android or Mac)
63 | validations:
64 | required: true
65 |
66 |
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE:
--------------------------------------------------------------------------------
1 |
2 |
3 |
31 |
32 |
--------------------------------------------------------------------------------
/.github/workflows/build.yml:
--------------------------------------------------------------------------------
1 | name: Go
2 |
3 | on:
4 | push:
5 | tags:
6 | - "*"
7 |
8 | jobs:
9 | build:
10 | runs-on: ubuntu-latest
11 | steps:
12 | - uses: actions/checkout@v3
13 | with:
14 | fetch-depth: 0
15 |
16 | - name: Set up Go
17 | uses: actions/setup-go@v3
18 | with:
19 | go-version: 1.21
20 | id: go
21 |
22 | - name: Test
23 | run: go mod tidy && make test
24 |
25 | - name: Run GoReleaser
26 | uses: goreleaser/goreleaser-action@v5
27 | with:
28 | distribution: goreleaser
29 | version: latest
30 | args: release --clean
31 | env:
32 | GITHUB_TOKEN: ${{ secrets.GO_RELEASER_GITHUB_TOKEN }}
33 |
--------------------------------------------------------------------------------
/.github/workflows/tests.yml:
--------------------------------------------------------------------------------
1 | name: Go
2 |
3 | on:
4 | push:
5 | branches: [ main, dev ]
6 |
7 | jobs:
8 |
9 | build:
10 | runs-on: ubuntu-latest
11 | steps:
12 | - uses: actions/checkout@v3
13 |
14 | - name: Set up Go
15 | uses: actions/setup-go@v3
16 | with:
17 | go-version: 1.21
18 |
19 | - name: Test
20 | run: go mod tidy && make test
21 |
22 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | *.[56789ao]
3 | *.a[56789o]
4 | *.so
5 | *.pyc
6 | ._*
7 | .nfs.*
8 | [56789a].out
9 | *~
10 | *.orig
11 | *.rej
12 | *.exe
13 | .*.swp
14 | core
15 | *.cgo*.go
16 | *.cgo*.c
17 | _cgo_*
18 | _obj
19 | _test
20 | _testmain.go
21 | /VERSION.cache
22 | /bin/
23 | /build.out
24 | /doc/articles/wiki/*.bin
25 | /goinstall.log
26 | /last-change
27 | /misc/cgo/life/run.out
28 | /misc/cgo/stdio/run.out
29 | /misc/cgo/testso/main
30 | /pkg/
31 | /src/*.*/
32 | /src/cmd/cgo/zdefaultcc.go
33 | /src/cmd/dist/dist
34 | /src/cmd/go/internal/cfg/zdefaultcc.go
35 | /src/cmd/go/internal/cfg/zosarch.go
36 | /src/cmd/internal/objabi/zbootstrap.go
37 | /src/go/build/zcgo.go
38 | /src/go/doc/headscan
39 | /src/runtime/internal/sys/zversion.go
40 | /src/unicode/maketables
41 | /test.out
42 | /test/garbage/*.out
43 | /test/pass.out
44 | /test/run.out
45 | /test/times.out
46 |
47 | #Personal
48 |
49 | testbinaries/
50 | tests_random/
51 | nuru
52 | Notes.md
53 | tutorials/en/*
54 | config.json
55 | *local*
56 |
57 | # For Nuru executables
58 | /nuru
59 | /Nuru
60 |
61 | dist/
62 |
--------------------------------------------------------------------------------
/.goreleaser.yaml:
--------------------------------------------------------------------------------
1 | project_name: nuru
2 | before:
3 | hooks:
4 | - go mod tidy
5 | - go generate ./...
6 |
7 | builds:
8 | - env:
9 | - CGO_ENABLED=0
10 | goos:
11 | - linux
12 | - windows
13 | - darwin
14 | - android
15 | ldflags:
16 | - "-s -w"
17 | ignore:
18 | - goos: android
19 | goarch: 386
20 |
21 | archives:
22 | - format: tar.gz
23 | name_template: >-
24 | nuru_
25 | {{- title .Os }}_
26 | {{- if eq .Arch "amd64" }}amd64
27 | {{- else if eq .Arch "386" }}i386
28 | {{- else }}{{ .Arch }}{{ end }}
29 | {{- if .Arm }}v{{ .Arm }}{{ end }}
30 | format_overrides:
31 | - goos: windows
32 | format: zip
33 |
34 | changelog:
35 | sort: asc
36 | filters:
37 | exclude:
38 | - "^docs:"
39 | - "^test:"
40 |
41 | nfpms:
42 | - maintainer: "AvicennaJr"
43 | homepage: "https://nuruprogramming.org"
44 | description: "Nuru is a programming language built from the ground up"
45 | formats:
46 | - deb
47 | file_name_template: "{{ .ProjectName }}.{{ .Os }}-{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}"
48 |
--------------------------------------------------------------------------------
/ABOUT.md:
--------------------------------------------------------------------------------
1 | # NURU PROGRAMMING LANGUAGE
2 |
3 | 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.
4 |
5 | ## Background
6 |
7 | 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.
8 |
9 | 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.
10 |
11 | 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:
12 | - 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.
13 | - 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.
14 |
15 | ## Purpose
16 |
17 | 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.
18 |
19 | 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.
20 |
21 | 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.
22 |
23 | ## Philosophy
24 |
25 | 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.
26 |
27 | Nuru is also community driven. We listen to our community and do our best to implement on the feedback we get from them.
28 |
29 | ## Where Not To Use Nuru
30 |
31 | 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.
32 |
33 | ## Challenges
34 |
35 | 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.
36 |
37 | ## Future Of Nuru
38 |
39 | 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.
40 |
41 | We also hope to see games and GUI applications written in Nuru in the near future... God willing.
42 |
43 | ## Final Words
44 |
45 | 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.
46 |
47 | And finally, I thank Allah for granting us the ability to learn and giving me the ability to make such a project.
48 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | VERSION=0.5.1
2 |
3 | build_linux:
4 | @echo 'building linux binary...'
5 | env GOOS=linux GOARCH=amd64 go build -ldflags="-s -w" -o nuru
6 | @echo 'shrinking binary...'
7 | ./upx --brute nuru
8 | @echo 'zipping build....'
9 | tar -zcvf nuru_linux_amd64_v${VERSION}.tar.gz nuru
10 | @echo 'cleaning up...'
11 | rm nuru
12 |
13 | build_windows:
14 | @echo 'building windows executable...'
15 | env GOOS=windows GOARCH=amd64 go build -ldflags="-s -w" -o nuru_windows_amd64_v${VERSION}.exe
16 | @echo 'shrinking build...'
17 | ./upx --brute nuru_windows_amd64_v${VERSION}.exe
18 |
19 | build_mac:
20 | @echo 'building mac binary...'
21 | env GOOS=darwin GOARCH=amd64 go build -ldflags="-s -w" -o nuru
22 | @echo 'shrinking binary...'
23 | ./upx --brute nuru
24 | @echo 'zipping build...'
25 | tar -zcvf nuru_mac_amd64_v${VERSION}.tar.gz nuru
26 | @echo 'cleaning up...'
27 | rm nuru
28 |
29 | build_android:
30 | @echo 'building android binary'
31 | env GOOS=android GOARCH=arm64 go build -ldflags="-s -w" -o nuru
32 | @echo 'zipping build...'
33 | tar -zcvf nuru_android_arm64_v${VERSION}.tar.gz nuru
34 | @echo 'cleaning up...'
35 | rm nuru
36 |
37 | build_test:
38 | go build -ldflags="-s -w" -o nuru
39 |
40 | dependencies:
41 | @echo 'checking dependencies...'
42 | go mod tidy
43 |
44 | test:
45 | @echo -e '\nTesting Lexer...'
46 | @./gotest --format testname ./lexer/
47 | @echo -e '\nTesting Parser...'
48 | @./gotest --format testname ./parser/
49 | @echo -e '\nTesting AST...'
50 | @./gotest --format testname ./ast/
51 | @echo -e '\nTesting Object...'
52 | @./gotest --format testname ./object/
53 | @echo -e '\nTesting Evaluator...'
54 | @./gotest --format testname ./evaluator/
55 |
56 | clean:
57 | go clean
58 |
--------------------------------------------------------------------------------
/assets/Nuru.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NuruProgramming/Nuru/0805bb2df91dda4040be58160f8db114cc84764f/assets/Nuru.png
--------------------------------------------------------------------------------
/assets/nuru-logo (Transparent).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NuruProgramming/Nuru/0805bb2df91dda4040be58160f8db114cc84764f/assets/nuru-logo (Transparent).png
--------------------------------------------------------------------------------
/ast/ast_test.go:
--------------------------------------------------------------------------------
1 | package ast
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/NuruProgramming/Nuru/token"
7 | )
8 |
9 | func TestString(t *testing.T) {
10 | program := &Program{
11 | Statements: []Statement{
12 | &LetStatement{
13 | Token: token.Token{Type: token.LET, Literal: "fanya"},
14 | Name: &Identifier{
15 | Token: token.Token{Type: token.IDENT, Literal: "myVar"},
16 | Value: "myVar",
17 | },
18 | Value: &Identifier{
19 | Token: token.Token{Type: token.IDENT, Literal: "anotherVar"},
20 | Value: "anotherVar",
21 | },
22 | },
23 | },
24 | }
25 |
26 | if program.String() != "fanya myVar = anotherVar;" {
27 | t.Errorf("program.String() wrong. got=%q", program.String())
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/evaluator/assign.go:
--------------------------------------------------------------------------------
1 | package evaluator
2 |
3 | import (
4 | "github.com/NuruProgramming/Nuru/ast"
5 | "github.com/NuruProgramming/Nuru/object"
6 | )
7 |
8 | func evalAssign(node *ast.Assign, env *object.Environment) object.Object {
9 | val := Eval(node.Value, env)
10 | if isError(val) {
11 | return val
12 | }
13 |
14 | obj := env.Set(node.Name.Value, val)
15 | return obj
16 | }
17 |
--------------------------------------------------------------------------------
/evaluator/assignEqual.go:
--------------------------------------------------------------------------------
1 | package evaluator
2 |
3 | import (
4 | "strings"
5 |
6 | "github.com/NuruProgramming/Nuru/ast"
7 | "github.com/NuruProgramming/Nuru/object"
8 | )
9 |
10 | func evalAssignEqual(node *ast.AssignEqual, env *object.Environment) object.Object {
11 | left := Eval(node.Left, env)
12 | if isError(left) {
13 | return left
14 | }
15 |
16 | value := Eval(node.Value, env)
17 | if isError(value) {
18 | return value
19 | }
20 |
21 | switch node.Token.Literal {
22 | case "+=":
23 | switch arg := left.(type) {
24 | case *object.Integer:
25 | switch val := value.(type) {
26 | case *object.Integer:
27 | v := arg.Value + val.Value
28 | return env.Set(node.Left.Token.Literal, &object.Integer{Value: v})
29 | case *object.Float:
30 | v := float64(arg.Value) + val.Value
31 | return env.Set(node.Left.Token.Literal, &object.Float{Value: v})
32 | default:
33 | return newError("Mstari %d: Huwezi kutumia '+=' kujumlisha %v na %v", node.Token.Line, arg.Type(), val.Type())
34 | }
35 | case *object.Float:
36 | switch val := value.(type) {
37 | case *object.Integer:
38 | v := arg.Value + float64(val.Value)
39 | return env.Set(node.Left.Token.Literal, &object.Float{Value: v})
40 | case *object.Float:
41 | v := arg.Value + val.Value
42 | return env.Set(node.Left.Token.Literal, &object.Float{Value: v})
43 | default:
44 | return newError("Mstari %d: Huwezi kutumia '+=' kujumlisha %v na %v", node.Token.Line, arg.Type(), val.Type())
45 | }
46 | case *object.String:
47 | switch val := value.(type) {
48 | case *object.String:
49 | v := arg.Value + val.Value
50 | return env.Set(node.Left.Token.Literal, &object.String{Value: v})
51 | default:
52 | return newError("Mstari %d: Huwezi kutumia '+=' kwa %v na %v", node.Token.Line, arg.Type(), val.Type())
53 | }
54 | default:
55 | return newError("Mstari %d: Huwezi kutumia '+=' na %v", node.Token.Line, arg.Type())
56 | }
57 | case "-=":
58 | switch arg := left.(type) {
59 | case *object.Integer:
60 | switch val := value.(type) {
61 | case *object.Integer:
62 | v := arg.Value - val.Value
63 | return env.Set(node.Left.Token.Literal, &object.Integer{Value: v})
64 | case *object.Float:
65 | v := float64(arg.Value) - val.Value
66 | return env.Set(node.Left.Token.Literal, &object.Float{Value: v})
67 | default:
68 | return newError("Mstari %d: Huwezi kutumia '-=' kujumlisha %v na %v", node.Token.Line, arg.Type(), val.Type())
69 | }
70 | case *object.Float:
71 | switch val := value.(type) {
72 | case *object.Integer:
73 | v := arg.Value - float64(val.Value)
74 | return env.Set(node.Left.Token.Literal, &object.Float{Value: v})
75 | case *object.Float:
76 | v := arg.Value - val.Value
77 | return env.Set(node.Left.Token.Literal, &object.Float{Value: v})
78 | default:
79 | return newError("Mstari %d: Huwezi kutumia '-=' kujumlisha %v na %v", node.Token.Line, arg.Type(), val.Type())
80 | }
81 | default:
82 | return newError("Mstari %d: Huwezi kutumia '-=' na %v", node.Token.Line, arg.Type())
83 | }
84 | case "*=":
85 | switch arg := left.(type) {
86 | case *object.Integer:
87 | switch val := value.(type) {
88 | case *object.Integer:
89 | v := arg.Value * val.Value
90 | return env.Set(node.Left.Token.Literal, &object.Integer{Value: v})
91 | case *object.Float:
92 | v := float64(arg.Value) * val.Value
93 | return env.Set(node.Left.Token.Literal, &object.Float{Value: v})
94 | case *object.String:
95 | v := strings.Repeat(val.Value, int(arg.Value))
96 | return env.Set(node.Left.Token.Literal, &object.String{Value: v})
97 | default:
98 | return newError("Mstari %d: Huwezi kutumia '*=' kujumlisha %v na %v", node.Token.Line, arg.Type(), val.Type())
99 | }
100 | case *object.Float:
101 | switch val := value.(type) {
102 | case *object.Integer:
103 | v := arg.Value * float64(val.Value)
104 | return env.Set(node.Left.Token.Literal, &object.Float{Value: v})
105 | case *object.Float:
106 | v := arg.Value * val.Value
107 | return env.Set(node.Left.Token.Literal, &object.Float{Value: v})
108 | default:
109 | return newError("Mstari %d: Huwezi kutumia '*=' kujumlisha %v na %v", node.Token.Line, arg.Type(), val.Type())
110 | }
111 | case *object.String:
112 | switch val := value.(type) {
113 | case *object.Integer:
114 | v := strings.Repeat(arg.Value, int(val.Value))
115 | return env.Set(node.Left.Token.Literal, &object.String{Value: v})
116 | default:
117 | return newError("Mstari %d: Huwezi kutumia '+=' kwa %v na %v", node.Token.Line, arg.Type(), val.Type())
118 | }
119 | default:
120 | return newError("Mstari %d: Huwezi kutumia '*=' na %v", node.Token.Line, arg.Type())
121 | }
122 | case "/=":
123 | switch arg := left.(type) {
124 | case *object.Integer:
125 | switch val := value.(type) {
126 | case *object.Integer:
127 | v := arg.Value / val.Value
128 | return env.Set(node.Left.Token.Literal, &object.Integer{Value: v})
129 | case *object.Float:
130 | v := float64(arg.Value) / val.Value
131 | return env.Set(node.Left.Token.Literal, &object.Float{Value: v})
132 | default:
133 | return newError("Mstari %d: Huwezi kutumia '/=' kujumlisha %v na %v", node.Token.Line, arg.Type(), val.Type())
134 | }
135 | case *object.Float:
136 | switch val := value.(type) {
137 | case *object.Integer:
138 | v := arg.Value / float64(val.Value)
139 | return env.Set(node.Left.Token.Literal, &object.Float{Value: v})
140 | case *object.Float:
141 | v := arg.Value / val.Value
142 | return env.Set(node.Left.Token.Literal, &object.Float{Value: v})
143 | default:
144 | return newError("Mstari %d: Huwezi kutumia '/=' kujumlisha %v na %v", node.Token.Line, arg.Type(), val.Type())
145 | }
146 | default:
147 | return newError("Mstari %d: Huwezi kutumia '/=' na %v", node.Token.Line, arg.Type())
148 | }
149 | default:
150 | return newError("Mstari %d: Operesheni Haifahamiki %s", node.Token.Line, node.Token.Literal)
151 | }
152 | }
153 |
--------------------------------------------------------------------------------
/evaluator/at.go:
--------------------------------------------------------------------------------
1 | package evaluator
2 |
3 | import (
4 | "github.com/NuruProgramming/Nuru/ast"
5 | "github.com/NuruProgramming/Nuru/object"
6 | )
7 |
8 | func evalAt(node *ast.At, env *object.Environment) object.Object {
9 | if at, ok := env.Get("@"); ok {
10 | return at
11 | }
12 | return newError("Iko nje ya scope")
13 | }
14 |
--------------------------------------------------------------------------------
/evaluator/bang.go:
--------------------------------------------------------------------------------
1 | package evaluator
2 |
3 | import "github.com/NuruProgramming/Nuru/object"
4 |
5 | func evalBangOperatorExpression(right object.Object) object.Object {
6 | switch right {
7 | case TRUE:
8 | return FALSE
9 | case FALSE:
10 | return TRUE
11 | case NULL:
12 | return TRUE
13 | default:
14 | return FALSE
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/evaluator/block.go:
--------------------------------------------------------------------------------
1 | package evaluator
2 |
3 | import (
4 | "github.com/NuruProgramming/Nuru/ast"
5 | "github.com/NuruProgramming/Nuru/object"
6 | )
7 |
8 | func evalBlockStatement(block *ast.BlockStatement, env *object.Environment) object.Object {
9 | var result object.Object
10 |
11 | for _, statement := range block.Statements {
12 | result = Eval(statement, env)
13 |
14 | if result != nil {
15 | rt := result.Type()
16 | if rt == object.RETURN_VALUE_OBJ || rt == object.ERROR_OBJ || rt == object.CONTINUE_OBJ || rt == object.BREAK_OBJ {
17 | return result
18 | }
19 | }
20 | }
21 |
22 | return result
23 | }
24 |
--------------------------------------------------------------------------------
/evaluator/call.go:
--------------------------------------------------------------------------------
1 | package evaluator
2 |
3 | import (
4 | "github.com/NuruProgramming/Nuru/ast"
5 | "github.com/NuruProgramming/Nuru/object"
6 | )
7 |
8 | func evalCall(node *ast.CallExpression, env *object.Environment) object.Object {
9 | function := Eval(node.Function, env)
10 |
11 | if isError(function) {
12 | return function
13 | }
14 |
15 | var args []object.Object
16 |
17 | switch fn := function.(type) {
18 | case *object.Function:
19 | args = evalArgsExpressions(node, fn, env)
20 | case *object.Package:
21 | obj, ok := fn.Scope.Get("andaa")
22 | if !ok {
23 | return newError("Pakeji haina 'andaa'")
24 | }
25 | args = evalArgsExpressions(node, obj.(*object.Function), env)
26 | default:
27 | args = evalExpressions(node.Arguments, env)
28 | }
29 |
30 | if len(args) == 1 && isError(args[0]) {
31 | return args[0]
32 | }
33 |
34 | return applyFunction(function, args, node.Token.Line)
35 | }
36 |
37 | func evalArgsExpressions(node *ast.CallExpression, fn *object.Function, env *object.Environment) []object.Object {
38 | argsList := &object.Array{}
39 | argsHash := &object.Dict{}
40 | argsHash.Pairs = make(map[object.HashKey]object.DictPair)
41 | for _, exprr := range node.Arguments {
42 | switch exp := exprr.(type) {
43 | case *ast.Assign:
44 | val := Eval(exp.Value, env)
45 | if isError(val) {
46 | return []object.Object{val}
47 | }
48 | var keyHash object.HashKey
49 | key := &object.String{Value: exp.Name.Value}
50 | keyHash = key.HashKey()
51 | pair := object.DictPair{Key: key, Value: val}
52 | argsHash.Pairs[keyHash] = pair
53 | default:
54 | evaluated := Eval(exp, env)
55 | if isError(evaluated) {
56 | return []object.Object{evaluated}
57 | }
58 | argsList.Elements = append(argsList.Elements, evaluated)
59 | }
60 | }
61 |
62 | var result []object.Object
63 | var params = map[string]bool{}
64 | for _, exp := range fn.Parameters {
65 | params[exp.Value] = true
66 | if len(argsList.Elements) > 0 {
67 | result = append(result, argsList.Elements[0])
68 | argsList.Elements = argsList.Elements[1:]
69 | } else {
70 | keyParam := &object.String{Value: exp.Value}
71 | keyParamHash := keyParam.HashKey()
72 | if valParam, ok := argsHash.Pairs[keyParamHash]; ok {
73 | result = append(result, valParam.Value)
74 | delete(argsHash.Pairs, keyParamHash)
75 | } else {
76 | if _e, _ok := fn.Defaults[exp.Value]; _ok {
77 | evaluated := Eval(_e, env)
78 | if isError(evaluated) {
79 | return []object.Object{evaluated}
80 | }
81 | result = append(result, evaluated)
82 | } else {
83 | return []object.Object{&object.Error{Message: "Tumekosa Hoja"}}
84 | }
85 | }
86 | }
87 | }
88 |
89 | for _, pair := range argsHash.Pairs {
90 | if _, ok := params[pair.Key.(*object.String).Value]; ok {
91 | return []object.Object{&object.Error{Message: "Tumepewa hoja nyingi kwa parameter moja"}}
92 | }
93 | }
94 |
95 | return result
96 |
97 | }
98 |
--------------------------------------------------------------------------------
/evaluator/dict.go:
--------------------------------------------------------------------------------
1 | package evaluator
2 |
3 | import (
4 | "github.com/NuruProgramming/Nuru/ast"
5 | "github.com/NuruProgramming/Nuru/object"
6 | )
7 |
8 | func evalDictLiteral(node *ast.DictLiteral, env *object.Environment) object.Object {
9 | pairs := make(map[object.HashKey]object.DictPair)
10 |
11 | for keyNode, valueNode := range node.Pairs {
12 | key := Eval(keyNode, env)
13 | if isError(key) {
14 | return key
15 | }
16 |
17 | hashKey, ok := key.(object.Hashable)
18 | if !ok {
19 | return newError("Mstari %d: Hashing imeshindikana: %s", node.Token.Line, key.Type())
20 | }
21 |
22 | value := Eval(valueNode, env)
23 | if isError(value) {
24 | return value
25 | }
26 |
27 | hashed := hashKey.HashKey()
28 | pairs[hashed] = object.DictPair{Key: key, Value: value}
29 | }
30 |
31 | return &object.Dict{Pairs: pairs}
32 | }
33 |
--------------------------------------------------------------------------------
/evaluator/forin.go:
--------------------------------------------------------------------------------
1 | package evaluator
2 |
3 | import (
4 | "github.com/NuruProgramming/Nuru/ast"
5 | "github.com/NuruProgramming/Nuru/object"
6 | )
7 |
8 | func evalForInExpression(fie *ast.ForIn, env *object.Environment, line int) object.Object {
9 | iterable := Eval(fie.Iterable, env)
10 | existingKeyIdentifier, okk := env.Get(fie.Key) // again, stay safe
11 | existingValueIdentifier, okv := env.Get(fie.Value)
12 | defer func() { // restore them later on
13 | if okk {
14 | env.Set(fie.Key, existingKeyIdentifier)
15 | }
16 | if okv {
17 | env.Set(fie.Value, existingValueIdentifier)
18 | }
19 | }()
20 | switch i := iterable.(type) {
21 | case object.Iterable:
22 | defer func() {
23 | i.Reset()
24 | }()
25 | return loopIterable(i.Next, env, fie)
26 | default:
27 | return newError("Mstari %d: Huwezi kufanya operesheni hii na %s", line, i.Type())
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/evaluator/function.go:
--------------------------------------------------------------------------------
1 | package evaluator
2 |
3 | import (
4 | "github.com/NuruProgramming/Nuru/ast"
5 | "github.com/NuruProgramming/Nuru/object"
6 | )
7 |
8 | func evalFunction(node *ast.FunctionLiteral, env *object.Environment) object.Object {
9 | function := &object.Function{
10 | Name: node.Name,
11 | Parameters: node.Parameters,
12 | Defaults: node.Defaults,
13 | Body: node.Body,
14 | Env: env,
15 | }
16 |
17 | return function
18 | }
19 |
--------------------------------------------------------------------------------
/evaluator/identifier.go:
--------------------------------------------------------------------------------
1 | package evaluator
2 |
3 | import (
4 | "github.com/NuruProgramming/Nuru/ast"
5 | "github.com/NuruProgramming/Nuru/object"
6 | )
7 |
8 | func evalIdentifier(node *ast.Identifier, env *object.Environment) object.Object {
9 | if val, ok := env.Get(node.Value); ok {
10 | return val
11 | }
12 | if builtin, ok := builtins[node.Value]; ok {
13 | return builtin
14 | }
15 |
16 | return newError("Mstari %d: Neno Halifahamiki: %s", node.Token.Line, node.Value)
17 | }
18 |
--------------------------------------------------------------------------------
/evaluator/if.go:
--------------------------------------------------------------------------------
1 | package evaluator
2 |
3 | import (
4 | "github.com/NuruProgramming/Nuru/ast"
5 | "github.com/NuruProgramming/Nuru/object"
6 | )
7 |
8 | func evalIfExpression(ie *ast.IfExpression, env *object.Environment) object.Object {
9 | condition := Eval(ie.Condition, env)
10 |
11 | if isError(condition) {
12 | return condition
13 | }
14 |
15 | if isTruthy(condition) {
16 | return Eval(ie.Consequence, env)
17 | } else if ie.Alternative != nil {
18 | return Eval(ie.Alternative, env)
19 | } else {
20 | return NULL
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/evaluator/import.go:
--------------------------------------------------------------------------------
1 | package evaluator
2 |
3 | import (
4 | "fmt"
5 | "os"
6 | "path/filepath"
7 | "strings"
8 |
9 | "github.com/NuruProgramming/Nuru/ast"
10 | "github.com/NuruProgramming/Nuru/lexer"
11 | "github.com/NuruProgramming/Nuru/module"
12 | "github.com/NuruProgramming/Nuru/object"
13 | "github.com/NuruProgramming/Nuru/parser"
14 | )
15 |
16 | var searchPaths []string
17 |
18 | func evalImport(node *ast.Import, env *object.Environment) object.Object {
19 | for k, v := range node.Identifiers {
20 | if mod, ok := module.Mapper[v.Value]; ok {
21 | env.Set(k, mod)
22 | } else {
23 | return evalImportFile(k, v, env)
24 | }
25 | }
26 | return NULL
27 | }
28 |
29 | func evalImportFile(name string, ident *ast.Identifier, env *object.Environment) object.Object {
30 | addSearchPath("")
31 | filename := findFile(name)
32 | if filename == "" {
33 | return newError("Moduli %s haipo", name)
34 | }
35 | var scope *object.Environment
36 | scope, err := evaluateFile(filename, env)
37 | if err != nil {
38 | return err
39 | }
40 | return importFile(name, ident, env, scope)
41 | }
42 |
43 | func addSearchPath(path string) {
44 | searchPaths = append(searchPaths, path)
45 | }
46 |
47 | func findFile(name string) string {
48 | basename := fmt.Sprintf("%s.nr", name)
49 | for _, path := range searchPaths {
50 | file := filepath.Join(path, basename)
51 | if fileExists(file) {
52 | return file
53 | }
54 | }
55 | return ""
56 | }
57 |
58 | func fileExists(file string) bool {
59 | _, err := os.Stat(file)
60 | return err == nil
61 | }
62 |
63 | func evaluateFile(file string, env *object.Environment) (*object.Environment, object.Object) {
64 | source, err := os.ReadFile(file)
65 | if err != nil {
66 | return nil, &object.Error{Message: fmt.Sprintf("Tumeshindwa kufungua pakeji: %s", file)}
67 | }
68 | l := lexer.New(string(source))
69 | p := parser.New(l)
70 | program := p.ParseProgram()
71 | if len(p.Errors()) != 0 {
72 | return nil, &object.Error{Message: fmt.Sprintf("Pakeji %s ina makosa yafuatayo:\n%s", file, strings.Join(p.Errors(), "\n"))}
73 | }
74 |
75 | scope := object.NewEnvironment()
76 | result := Eval(program, scope)
77 | if isError(result) {
78 | return nil, result
79 | }
80 | return scope, nil
81 | }
82 |
83 | func importFile(name string, ident *ast.Identifier, env *object.Environment, scope *object.Environment) object.Object {
84 | value, ok := scope.Get(ident.Value)
85 | if !ok {
86 | return newError("%s sio pakeji", name)
87 | }
88 | env.Set(name, value)
89 | return NULL
90 | }
91 |
--------------------------------------------------------------------------------
/evaluator/in.go:
--------------------------------------------------------------------------------
1 | package evaluator
2 |
3 | import (
4 | "strings"
5 |
6 | "github.com/NuruProgramming/Nuru/object"
7 | )
8 |
9 | func evalInExpression(left, right object.Object, line int) object.Object {
10 | switch right.(type) {
11 | case *object.String:
12 | return evalInStringExpression(left, right)
13 | case *object.Array:
14 | return evalInArrayExpression(left, right)
15 | case *object.Dict:
16 | return evalInDictExpression(left, right, line)
17 | default:
18 | return FALSE
19 | }
20 | }
21 |
22 | func evalInStringExpression(left, right object.Object) object.Object {
23 | if left.Type() != object.STRING_OBJ {
24 | return FALSE
25 | }
26 | leftVal := left.(*object.String)
27 | rightVal := right.(*object.String)
28 | found := strings.Contains(rightVal.Value, leftVal.Value)
29 | return nativeBoolToBooleanObject(found)
30 | }
31 |
32 | func evalInDictExpression(left, right object.Object, line int) object.Object {
33 | leftVal, ok := left.(object.Hashable)
34 | if !ok {
35 | return newError("Mstari %d: Huwezi kutumia kama 'key': %s", line, left.Type())
36 | }
37 | key := leftVal.HashKey()
38 | rightVal := right.(*object.Dict).Pairs
39 | _, ok = rightVal[key]
40 | return nativeBoolToBooleanObject(ok)
41 | }
42 |
43 | func evalInArrayExpression(left, right object.Object) object.Object {
44 | rightVal := right.(*object.Array)
45 | switch leftVal := left.(type) {
46 | case *object.Null:
47 | for _, v := range rightVal.Elements {
48 | if v.Type() == object.NULL_OBJ {
49 | return TRUE
50 | }
51 | }
52 | case *object.String:
53 | for _, v := range rightVal.Elements {
54 | if v.Type() == object.STRING_OBJ {
55 | elem := v.(*object.String)
56 | if elem.Value == leftVal.Value {
57 | return TRUE
58 | }
59 | }
60 | }
61 | case *object.Integer:
62 | for _, v := range rightVal.Elements {
63 | if v.Type() == object.INTEGER_OBJ {
64 | elem := v.(*object.Integer)
65 | if elem.Value == leftVal.Value {
66 | return TRUE
67 | }
68 | }
69 | }
70 | case *object.Float:
71 | for _, v := range rightVal.Elements {
72 | if v.Type() == object.FLOAT_OBJ {
73 | elem := v.(*object.Float)
74 | if elem.Value == leftVal.Value {
75 | return TRUE
76 | }
77 | }
78 | }
79 | }
80 | return FALSE
81 | }
82 |
--------------------------------------------------------------------------------
/evaluator/index.go:
--------------------------------------------------------------------------------
1 | package evaluator
2 |
3 | import "github.com/NuruProgramming/Nuru/object"
4 |
5 | func evalIndexExpression(left, index object.Object, line int) object.Object {
6 | switch {
7 | case left.Type() == object.ARRAY_OBJ && index.Type() == object.INTEGER_OBJ:
8 | return evalArrayIndexExpression(left, index)
9 | case left.Type() == object.ARRAY_OBJ && index.Type() != object.INTEGER_OBJ:
10 | return newError("Mstari %d: Tafadhali tumia number, sio: %s", line, index.Type())
11 | case left.Type() == object.DICT_OBJ:
12 | return evalDictIndexExpression(left, index, line)
13 | default:
14 | return newError("Mstari %d: Operesheni hii haiwezekani kwa: %s", line, left.Type())
15 | }
16 | }
17 |
18 | func evalArrayIndexExpression(array, index object.Object) object.Object {
19 | arrayObject := array.(*object.Array)
20 | idx := index.(*object.Integer).Value
21 | max := int64(len(arrayObject.Elements) - 1)
22 |
23 | if idx < 0 || idx > max {
24 | return NULL
25 | }
26 |
27 | return arrayObject.Elements[idx]
28 | }
29 |
30 | func evalDictIndexExpression(dict, index object.Object, line int) object.Object {
31 | dictObject := dict.(*object.Dict)
32 |
33 | key, ok := index.(object.Hashable)
34 | if !ok {
35 | return newError("Mstari %d: Samahani, %s haitumiki kama ufunguo", line, index.Type())
36 | }
37 |
38 | pair, ok := dictObject.Pairs[key.HashKey()]
39 | if !ok {
40 | return NULL
41 | }
42 |
43 | return pair.Value
44 | }
45 |
--------------------------------------------------------------------------------
/evaluator/method.go:
--------------------------------------------------------------------------------
1 | package evaluator
2 |
3 | import (
4 | "github.com/NuruProgramming/Nuru/ast"
5 | "github.com/NuruProgramming/Nuru/object"
6 | )
7 |
8 | func evalMethodExpression(node *ast.MethodExpression, env *object.Environment) object.Object {
9 | obj := Eval(node.Object, env)
10 | if isError(obj) {
11 | return obj
12 | }
13 | args := evalExpressions(node.Arguments, env)
14 | if len(args) == 1 && isError(args[0]) {
15 | return args[0]
16 | }
17 |
18 | defs := make(map[string]object.Object)
19 |
20 | for k, v := range node.Defaults {
21 | defs[k] = Eval(v, env)
22 | }
23 | return applyMethod(obj, node.Method, args, defs, node.Token.Line)
24 | }
25 |
26 | func applyMethod(obj object.Object, method ast.Expression, args []object.Object, defs map[string]object.Object, l int) object.Object {
27 | switch obj := obj.(type) {
28 | case *object.String:
29 | return obj.Method(method.(*ast.Identifier).Value, args)
30 | case *object.File:
31 | return obj.Method(method.(*ast.Identifier).Value, args)
32 | case *object.Time:
33 | return obj.Method(method.(*ast.Identifier).Value, args, defs)
34 | case *object.Array:
35 | switch method.(*ast.Identifier).Value {
36 | case "map":
37 | return maap(obj, args)
38 | case "chuja":
39 | return filter(obj, args)
40 | default:
41 | return obj.Method(method.(*ast.Identifier).Value, args)
42 | }
43 | case *object.Module:
44 | if fn, ok := obj.Functions[method.(*ast.Identifier).Value]; ok {
45 | return fn(args, defs)
46 | }
47 | case *object.Instance:
48 | if fn, ok := obj.Package.Scope.Get(method.(*ast.Identifier).Value); ok {
49 | fn.(*object.Function).Env.Set("@", obj)
50 | ret := applyFunction(fn, args, l)
51 | fn.(*object.Function).Env.Del("@")
52 | return ret
53 | }
54 | case *object.Package:
55 | if fn, ok := obj.Scope.Get(method.(*ast.Identifier).Value); ok {
56 | fn.(*object.Function).Env.Set("@", obj)
57 | ret := applyFunction(fn, args, l)
58 | fn.(*object.Function).Env.Del("@")
59 | return ret
60 | }
61 | }
62 | return newError("Samahani, %s haina function '%s()'", obj.Inspect(), method.(*ast.Identifier).Value)
63 | }
64 |
65 | // ///////////////////////////////////////////////////////////////
66 | // //////// Some methods here because of loop dependency ////////
67 | // /////////////////////////////////////////////////////////////
68 | func maap(a *object.Array, args []object.Object) object.Object {
69 | if len(args) != 1 && args[0].Type() != object.FUNCTION_OBJ {
70 | return newError("Samahani, hoja sii sahihi")
71 | }
72 |
73 | fn, ok := args[0].(*object.Function)
74 | if !ok {
75 | return newError("Samahani, hoja sii sahihi")
76 | }
77 | env := object.NewEnvironment()
78 | newArr := object.Array{Elements: []object.Object{}}
79 | for _, obj := range a.Elements {
80 | env.Set(fn.Parameters[0].Value, obj)
81 | r := Eval(fn.Body, env)
82 | if o, ok := r.(*object.ReturnValue); ok {
83 | r = o.Value
84 | }
85 | newArr.Elements = append(newArr.Elements, r)
86 | }
87 | return &newArr
88 | }
89 |
90 | func filter(a *object.Array, args []object.Object) object.Object {
91 | if len(args) != 1 && args[0].Type() != object.FUNCTION_OBJ {
92 | return newError("Samahani, hoja sii sahihi")
93 | }
94 |
95 | fn, ok := args[0].(*object.Function)
96 | if !ok {
97 | return newError("Samahani, hoja sii sahihi")
98 | }
99 | env := object.NewEnvironment()
100 | newArr := object.Array{Elements: []object.Object{}}
101 | for _, obj := range a.Elements {
102 | env.Set(fn.Parameters[0].Value, obj)
103 | cond := Eval(fn.Body, env)
104 | if cond.Inspect() == "kweli" {
105 | newArr.Elements = append(newArr.Elements, obj)
106 | }
107 | }
108 | return &newArr
109 | }
110 |
--------------------------------------------------------------------------------
/evaluator/package.go:
--------------------------------------------------------------------------------
1 | package evaluator
2 |
3 | import (
4 | "github.com/NuruProgramming/Nuru/ast"
5 | "github.com/NuruProgramming/Nuru/object"
6 | )
7 |
8 | func evalPackage(node *ast.Package, env *object.Environment) object.Object {
9 | pakeji := &object.Package{
10 | Name: node.Name,
11 | Env: env,
12 | Scope: object.NewEnclosedEnvironment(env),
13 | }
14 |
15 | Eval(node.Block, pakeji.Scope)
16 | env.Set(node.Name.Value, pakeji)
17 | return pakeji
18 | }
19 |
--------------------------------------------------------------------------------
/evaluator/postfix.go:
--------------------------------------------------------------------------------
1 | package evaluator
2 |
3 | import (
4 | "github.com/NuruProgramming/Nuru/ast"
5 | "github.com/NuruProgramming/Nuru/object"
6 | )
7 |
8 | func evalPostfixExpression(env *object.Environment, operator string, node *ast.PostfixExpression) object.Object {
9 | val, ok := env.Get(node.Token.Literal)
10 | if !ok {
11 | return newError("Tumia KITAMBULISHI CHA NAMBA AU DESIMALI, sio %s", node.Token.Type)
12 | }
13 | switch operator {
14 | case "++":
15 | switch arg := val.(type) {
16 | case *object.Integer:
17 | v := arg.Value + 1
18 | return env.Set(node.Token.Literal, &object.Integer{Value: v})
19 | case *object.Float:
20 | v := arg.Value + 1
21 | return env.Set(node.Token.Literal, &object.Float{Value: v})
22 | default:
23 | 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)
24 |
25 | }
26 | case "--":
27 | switch arg := val.(type) {
28 | case *object.Integer:
29 | v := arg.Value - 1
30 | return env.Set(node.Token.Literal, &object.Integer{Value: v})
31 | case *object.Float:
32 | v := arg.Value - 1
33 | return env.Set(node.Token.Literal, &object.Float{Value: v})
34 | default:
35 | 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)
36 | }
37 | default:
38 | return newError("Haifahamiki: %s", operator)
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/evaluator/prefix.go:
--------------------------------------------------------------------------------
1 | package evaluator
2 |
3 | import "github.com/NuruProgramming/Nuru/object"
4 |
5 | func evalMinusPrefixOperatorExpression(right object.Object, line int) object.Object {
6 | switch obj := right.(type) {
7 |
8 | case *object.Integer:
9 | return &object.Integer{Value: -obj.Value}
10 |
11 | case *object.Float:
12 | return &object.Float{Value: -obj.Value}
13 |
14 | default:
15 | return newError("Mstari %d: Operesheni Haieleweki: -%s", line, right.Type())
16 | }
17 | }
18 | func evalPlusPrefixOperatorExpression(right object.Object, line int) object.Object {
19 | switch obj := right.(type) {
20 |
21 | case *object.Integer:
22 | return &object.Integer{Value: obj.Value}
23 |
24 | case *object.Float:
25 | return &object.Float{Value: obj.Value}
26 |
27 | default:
28 | return newError("Mstari %d: Operesheni Haieleweki: +%s", line, right.Type())
29 | }
30 | }
31 |
32 | func evalPrefixExpression(operator string, right object.Object, line int) object.Object {
33 | switch operator {
34 | case "!":
35 | return evalBangOperatorExpression(right)
36 | case "-":
37 | return evalMinusPrefixOperatorExpression(right, line)
38 | case "+":
39 | return evalPlusPrefixOperatorExpression(right, line)
40 | default:
41 | return newError("Mstari %d: Operesheni Haieleweki: %s%s", line, operator, right.Type())
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/evaluator/property.go:
--------------------------------------------------------------------------------
1 | package evaluator
2 |
3 | import (
4 | "github.com/NuruProgramming/Nuru/ast"
5 | "github.com/NuruProgramming/Nuru/object"
6 | )
7 |
8 | func evalPropertyExpression(node *ast.PropertyExpression, env *object.Environment) object.Object {
9 | left := Eval(node.Object, env)
10 | if isError(left) {
11 | return left
12 | }
13 | switch left.(type) {
14 | case *object.Instance:
15 | obj := left.(*object.Instance)
16 | prop := node.Property.(*ast.Identifier).Value
17 | if val, ok := obj.Env.Get(prop); ok {
18 | return val
19 | }
20 | case *object.Package:
21 | obj := left.(*object.Package)
22 | prop := node.Property.(*ast.Identifier).Value
23 | if val, ok := obj.Env.Get(prop); ok {
24 | return val
25 | }
26 | // case *object.Module:
27 | // mod := left.(*object.Module)
28 | // prop := node.Property.(*ast.Identifier).Value
29 | // if val, ok := mod.Properties[prop]; ok {
30 | // return val()
31 | // }
32 | }
33 | return newError("Value %s sii sahihi kwenye %s", node.Property.(*ast.Identifier).Value, left.Inspect())
34 | }
35 |
36 | func evalPropertyAssignment(name *ast.PropertyExpression, val object.Object, env *object.Environment) object.Object {
37 | left := Eval(name.Object, env)
38 | if isError(left) {
39 | return left
40 | }
41 | switch left.(type) {
42 | case *object.Instance:
43 | obj := left.(*object.Instance)
44 | prop := name.Property.(*ast.Identifier).Value
45 | if _, ok := obj.Env.Get(prop); ok {
46 | obj.Env.Set(prop, val)
47 | return NULL
48 | }
49 | obj.Env.Set(prop, val)
50 | return NULL
51 | case *object.Package:
52 | obj := left.(*object.Package)
53 | prop := name.Property.(*ast.Identifier).Value
54 | if _, ok := obj.Env.Get(prop); ok {
55 | obj.Env.Set(prop, val)
56 | return NULL
57 | }
58 | obj.Env.Set(prop, val)
59 | return NULL
60 | default:
61 | return newError("Imeshindikana kuweka kwenye pakiti %s", left.Type())
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/evaluator/switch.go:
--------------------------------------------------------------------------------
1 | package evaluator
2 |
3 | import (
4 | "github.com/NuruProgramming/Nuru/ast"
5 | "github.com/NuruProgramming/Nuru/object"
6 | )
7 |
8 | func evalSwitchStatement(se *ast.SwitchExpression, env *object.Environment) object.Object {
9 | obj := Eval(se.Value, env)
10 | for _, opt := range se.Choices {
11 |
12 | if opt.Default {
13 | continue
14 | }
15 | for _, val := range opt.Expr {
16 | out := Eval(val, env)
17 | if obj.Type() == out.Type() && obj.Inspect() == out.Inspect() {
18 | blockOut := evalBlockStatement(opt.Block, env)
19 | return blockOut
20 | }
21 | }
22 | }
23 | for _, opt := range se.Choices {
24 | if opt.Default {
25 | out := evalBlockStatement(opt.Block, env)
26 | return out
27 | }
28 | }
29 | return nil
30 | }
31 |
--------------------------------------------------------------------------------
/evaluator/type.go:
--------------------------------------------------------------------------------
1 | package evaluator
2 |
3 | import (
4 | "strconv"
5 |
6 | "github.com/NuruProgramming/Nuru/object"
7 | )
8 |
9 | func convertToInteger(obj object.Object) object.Object {
10 | switch obj := obj.(type) {
11 | case *object.Integer:
12 | return obj
13 | case *object.Float:
14 | return &object.Integer{Value: int64(obj.Value)}
15 | case *object.String:
16 | i, err := strconv.ParseInt(obj.Value, 10, 64)
17 | if err != nil {
18 | return newError("Haiwezi kubadilisha '%s' kuwa NAMBA", obj.Value)
19 | }
20 | return &object.Integer{Value: i}
21 | case *object.Boolean:
22 | if obj.Value {
23 | return &object.Integer{Value: 1}
24 | }
25 | return &object.Integer{Value: 0}
26 | default:
27 | return newError("Haiwezi kubadilisha %s kuwa NAMBA", obj.Type())
28 | }
29 | }
30 |
31 | func convertToFloat(obj object.Object) object.Object {
32 | switch obj := obj.(type) {
33 | case *object.Float:
34 | return obj
35 | case *object.Integer:
36 | return &object.Float{Value: float64(obj.Value)}
37 | case *object.String:
38 | f, err := strconv.ParseFloat(obj.Value, 64)
39 | if err != nil {
40 | return newError("Haiwezi kubadilisha '%s' kuwa DESIMALI", obj.Value)
41 | }
42 | return &object.Float{Value: f}
43 | case *object.Boolean:
44 | if obj.Value {
45 | return &object.Float{Value: 1.0}
46 | }
47 | return &object.Float{Value: 0.0}
48 | default:
49 | return newError("Haiwezi kubadilisha %s kuwa DESIMALI", obj.Type())
50 | }
51 | }
52 |
53 | func convertToString(obj object.Object) object.Object {
54 | return &object.String{Value: obj.Inspect()}
55 | }
56 |
57 | func convertToBoolean(obj object.Object) object.Object {
58 | switch obj := obj.(type) {
59 | case *object.Boolean:
60 | return obj
61 | case *object.Integer:
62 | return &object.Boolean{Value: obj.Value != 0}
63 | case *object.Float:
64 | return &object.Boolean{Value: obj.Value != 0}
65 | case *object.String:
66 | return &object.Boolean{Value: len(obj.Value) > 0}
67 | case *object.Null:
68 | return &object.Boolean{Value: false}
69 | default:
70 | return &object.Boolean{Value: true}
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/evaluator/while.go:
--------------------------------------------------------------------------------
1 | package evaluator
2 |
3 | import (
4 | "github.com/NuruProgramming/Nuru/ast"
5 | "github.com/NuruProgramming/Nuru/object"
6 | )
7 |
8 | func evalWhileExpression(we *ast.WhileExpression, env *object.Environment) object.Object {
9 | condition := Eval(we.Condition, env)
10 | var evaluated object.Object
11 | if isError(condition) {
12 | return condition
13 | }
14 | if isTruthy(condition) {
15 | evaluated = Eval(we.Consequence, env)
16 | if isError(evaluated) {
17 | return evaluated
18 | }
19 | if evaluated != nil && evaluated.Type() == object.BREAK_OBJ {
20 | return evaluated
21 | }
22 | evaluated = evalWhileExpression(we, env)
23 | }
24 | return evaluated
25 | }
26 |
--------------------------------------------------------------------------------
/examples/Astart.nr:
--------------------------------------------------------------------------------
1 | /*############ A*(A-star) Algorithm ##############
2 |
3 | By @VictorKariuki
4 |
5 | https://github.com/VictorKariuki
6 |
7 | ################################################*/
8 |
9 |
10 | // create a list of numbers
11 | fanya list = unda(first,last,interval){
12 | fanya list = [first];
13 | fanya i = first + interval;
14 | wakati(i < last){
15 | list.sukuma(i)
16 | i+=interval;
17 | }
18 | rudisha list;
19 | }
20 |
21 | // Maths functions
22 | // find the absolute value of a number
23 | fanya abs_namba = unda(namba){
24 | kama(namba < 0){
25 | rudisha -1 * namba;
26 | }
27 |
28 | rudisha namba;
29 | }
30 |
31 | // square a number
32 | fanya square = unda(n, i, j){
33 | fanya kati = (i+j)/2;
34 | fanya mul = kati * kati;
35 | fanya abs_diff = abs_namba(mul-n);
36 |
37 | kama (mul == n || abs_diff < 0.00001){
38 | rudisha kati;
39 | }au kama(mul < n){
40 | rudisha square(n,kati,j)
41 | }au{
42 | rudisha square(n,i,kati)
43 | }
44 | }
45 |
46 | // find the square root of a number
47 | fanya sqrt = unda(namba){
48 | kwa i ktk list(0,namba,1) {
49 | kama((i*i )== namba){
50 | rudisha i;
51 | }au kama ((i*i )> namba){
52 | rudisha square(namba,i-1,i)
53 | }
54 | }
55 | }
56 |
57 | // Main function
58 | fanya aStar = unda(start, goal) {
59 | // Initialize the open and closed lists
60 | fanya openList = [start];
61 | fanya closedList = [];
62 |
63 | fanya reconstructPath = unda(node) {
64 | fanya path = [node];
65 | wakati (node["parent"]) {
66 | path = [node["parent"]] + path;
67 | node = node["parent"];
68 | }
69 | rudisha path;
70 | }
71 |
72 | fanya heuristic = unda(node1, node2) {
73 | // Calculate the Euclidean distance between the nodes' positions
74 | fanya dx = node1["x"] - node2["x"];
75 | fanya dy = node1["y"] - node2["y"];
76 | rudisha sqrt(dx * dx + dy * dy);
77 | }
78 |
79 | fanya findMinNode = unda(openList) {
80 | fanya i = 1;
81 | fanya minNode = openList[0];
82 |
83 | wakati (i < openList.idadi()) {
84 | fanya node = openList[i];
85 | kama (node["f"] < minNode["f"]) {
86 | minNode = node;
87 | }
88 | i++
89 | }
90 |
91 | rudisha minNode;
92 | }
93 |
94 | fanya removeNodeFromArray = unda(array, node) {
95 | fanya newArray = [];
96 | fanya i = 1;
97 | wakati (i < array.idadi()) {
98 | kama (array[i] != node) {
99 | newArray.sukuma(array[i]);
100 | }
101 | i++;
102 | }
103 | rudisha newArray;
104 | }
105 |
106 | fanya urefu = unda(node1, node2) {
107 | // Assume all edges have a cost of 1
108 | rudisha 1;
109 | }
110 |
111 | // Initialize the g and f scores of the starting node
112 | start["g"] = 0;
113 | start["f"] = start["g"] + heuristic(start, goal);
114 |
115 |
116 |
117 | // Start the search loop
118 | wakati (openList.idadi() > 0) {
119 | // Find the node with the lowest f score in the open list
120 | fanya current = findMinNode(openList);
121 |
122 | // Check kama the goal node has been reached
123 | kama (current == goal) {
124 | rudisha reconstructPath(current);
125 | }
126 |
127 | // Move the current node from the open to the closed list
128 | openList = removeNodeFromArray(openList, current);
129 |
130 | closedList.sukuma(current);
131 |
132 | // Explore the neighbors of the current node
133 | kwa neighbor ktk current["neighbors"] {
134 | // Skip neighbors that are in the closed list
135 | kama (neighbor ktk closedList) {
136 | endelea
137 | }
138 |
139 | // Calculate the tentative g score of the neighbor
140 | fanya tentativeG = start["g"] + urefu(current, neighbor);
141 |
142 | // Check kama the neighbor is in the open list
143 | fanya tentativeIsBetter = sikweli;
144 | kama (!(neighbor ktk openList)) {
145 | openList.sukuma(neighbor);
146 | tentativeIsBetter = kweli;
147 | } au kama (tentativeG < neighbor["g"]) {
148 | tentativeIsBetter = kweli;
149 | }
150 |
151 | // Update the neighbor's g score kama the tentative score is better
152 | kama (tentativeIsBetter) {
153 | neighbor["g"] = tentativeG;
154 | neighbor["f"] = neighbor["g"] + heuristic(neighbor, goal);
155 | neighbor["parent"] = current;
156 | }
157 | }
158 | }
159 |
160 | // kama the open list is empty, no path was found
161 | rudisha tupu;
162 | }
163 |
164 | // Define the nodes of the graph
165 | fanya nodeA = { "x": 0, "y": 0, "neighbors": [] };
166 | fanya nodeB = { "x": 1, "y": 2, "neighbors": [] };
167 | fanya nodeC = { "x": 3, "y": 1, "neighbors": [] };
168 | fanya nodeD = { "x": 4, "y": 3, "neighbors": [] };
169 |
170 | // Define the edges between the nodes
171 | nodeA["neighbors"] = [nodeB];
172 | nodeB["neighbors"] = [nodeA, nodeC];
173 | nodeC["neighbors"] = [nodeB, nodeD];
174 | nodeD["neighbors"] = [nodeC];
175 |
176 | // Call the A* function with the start and goal nodes and the heuristic and distance functions
177 | //fanya path = aStar(nodeA, nodeC);
178 |
179 | andika(nodeA);
--------------------------------------------------------------------------------
/examples/reduce.nr:
--------------------------------------------------------------------------------
1 | fanya reduce = unda(iterator, callback, initialValue) {
2 | fanya accumulator = initialValue;
3 |
4 | kwa thamani ktk iterator {
5 | accumulator = callback(accumulator, thamani);
6 | }
7 |
8 | rudisha accumulator;
9 | }
10 |
11 | fanya list = [1,2,3,4,5];
12 | fanya employees = [{"salary":120},{"salary":135},{"salary":140}]
13 |
14 | fanya sum = unda(acc,value){
15 | rudisha acc + value;
16 | }
17 |
18 | fanya mul = unda(acc,value){
19 | rudisha acc * value;
20 | }
21 |
22 | fanya sumSalo = unda(acc,value){
23 | rudisha acc + value["salary"];
24 | }
25 |
26 | fanya sumSaloWithTax = unda(acc,value){
27 | rudisha acc + (value["salary"] * (1-0.34));
28 | }
29 |
30 | andika(reduce(list,sum,0))
31 | andika(reduce(list,mul,1))
32 |
33 | andika(reduce(employees,sumSalo,0))
34 | andika(reduce(employees,sumSaloWithTax,0))
--------------------------------------------------------------------------------
/examples/sarufi.nr:
--------------------------------------------------------------------------------
1 | tumia mtandao
2 | tumia jsoni
3 | pakeji sarufi {
4 | andaa = unda(file) {
5 | config = fungua(file)
6 | configString = config.soma()
7 | configDict = jsoni.dikodi(configString)
8 | clientID = configDict["client_id"]
9 | clientSecret = configDict["client_secret"]
10 | params = {"client_id": clientID, "client_secret": clientSecret}
11 | tokenString = mtandao.tuma(yuareli="https://api.sarufi.io/api/access_token", mwili=params)
12 | tokenDict = jsoni.dikodi(tokenString)
13 | @.token = tokenDict["access_token"]
14 | @.Auth = "Bearer " + @.token
15 | }
16 |
17 | tokenYangu = unda() {
18 | rudisha @.token
19 | }
20 |
21 | tengenezaChatbot = unda(data) {
22 | majibu = mtandao.tuma(yuareli="https://api.sarufi.io/chatbot", vichwa={"Authorization": @.Auth}, mwili = data)
23 | rudisha majibu
24 | }
25 |
26 | pataChatbotZote = unda() {
27 | majibu = mtandao.peruzi(yuareli="https://api.sarufi.io/chatbots", vichwa={"Authorization": @.Auth})
28 | rudisha majibu
29 | }
30 | }
31 |
32 |
33 |
--------------------------------------------------------------------------------
/examples/sorting_algorithm.nr:
--------------------------------------------------------------------------------
1 | /*
2 | ############ Sorting Algorithm ##############
3 |
4 | By @VictorKariuki
5 |
6 | https://github.com/VictorKariuki
7 |
8 | #############################################
9 | */
10 |
11 | slice = unda(arr,start, end) {
12 | result = []
13 | wakati (start < end) {
14 | result = result + [arr[start]]
15 | start = start + 1
16 | }
17 | rudisha result
18 | }
19 |
20 | merge = unda(left, right) {
21 | result = []
22 | lLen = left.idadi()
23 | rLen = right.idadi()
24 | l = 0
25 | r = 0
26 | wakati (l < lLen && r < rLen) {
27 | kama (left[l] < right[r]) {
28 | result = result + [left[l]]
29 | l = l + 1
30 | } sivyo {
31 | result = result + [right[r]]
32 | r = r + 1
33 | }
34 | }
35 | andika(result)
36 | }
37 |
38 |
39 | mergeSort = unda(arr){
40 | len = arr.idadi()
41 | andika("arr is ", arr," of length ", len)
42 | kama (len < 2) {
43 | rudisha arr
44 | }
45 | andika("len is greater than or == to 2", len > 1)
46 |
47 | mid = (len / 2)
48 | andika("arr has a mid point of ", mid)
49 |
50 | left = slice(arr, 0, mid)
51 | right = slice(arr, mid, len)
52 | andika("left slice is ", left)
53 | andika("right slice is ", right)
54 | sortedLeft = mergeSort(left)
55 | sortedRight = mergeSort(right)
56 | andika("sortedLeft is ", sortedLeft)
57 | andika("sortedRight is ", sortedRight)
58 | rudisha merge(sortedLeft, sortedRight)
59 | }
60 |
61 | arr = [6, 5, 3, 1, 8, 7, 2, 4]
62 | sortedArray = mergeSort(arr)
63 | andika(sortedArray)
64 |
--------------------------------------------------------------------------------
/examples/sudoku_solver.nr:
--------------------------------------------------------------------------------
1 | /*########### Backtracking Algorithm ##############
2 |
3 | By @VictorKariuki
4 |
5 | https://github.com/VictorKariuki
6 |
7 | NURU program to solve Sudoku using Backtracking Algorithm
8 |
9 | The sudoku puzzle is represented as a 2D array. The empty
10 | cells are represented by 0. The algorithm works by trying
11 | out all possible numbers for an empty cell. If the number
12 | is valid, it is placed in the cell. If the number is invalid,
13 | the algorithm backtracks to the previous cell and tries
14 | another number. The algorithm terminates when all cells
15 | are filled. The algorithm is implemented in the solveSudoku
16 | function. The isValid function checks kama a number is
17 | valid in a given cell. The printSudoku function prints
18 | the sudoku puzzle. The solveSudoku function solves the
19 | sudoku puzzle. The main function initializes the sudoku
20 | puzzle and calls the solveSudoku function.
21 |
22 | #################################################*/
23 |
24 |
25 | fanya printing = unda(sudoku) {
26 | fanya row = 0
27 | wakati (row < 9){
28 | andika(sudoku[row])
29 | row++
30 | }
31 | }
32 |
33 | 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]]
34 |
35 |
36 |
37 | fanya isSafe = unda(grid, row, col, num) {
38 | kwa x ktk [0,1,2,3,4,5,6,7,8] {
39 | kama (grid[row][x] == num) {
40 | rudisha sikweli
41 | }
42 | }
43 |
44 | kwa x ktk [0,1,2,3,4,5,6,7,8] {
45 | kama (grid[x][col] == num) {
46 | rudisha sikweli
47 | }
48 | }
49 |
50 | fanya startRow = row - row % 3
51 | fanya startCol = col - col % 3
52 |
53 | kwa i ktk [0, 1, 2] {
54 | kwa j ktk [0, 1, 2] {
55 | kama (grid[i + startRow][j + startCol] == num) {
56 | rudisha sikweli
57 | }
58 | }
59 | }
60 |
61 | rudisha kweli
62 | }
63 |
64 | fanya solveSudoku = unda(grid, row, col) {
65 | kama (row == 8 && col == 9) {
66 | rudisha kweli
67 | }
68 |
69 | kama (col == 9) {
70 | row += 1
71 | col = 0
72 | }
73 |
74 | kama (grid[row][col] > 0) {
75 | rudisha solveSudoku(grid, row, col + 1)
76 | }
77 |
78 | kwa num ktk [1,2,3,4,5,6,7,8,9] {
79 | kama (isSafe(grid, row, col, num)) {
80 | grid[row][col] = num
81 | kama (solveSudoku(grid, row, col + 1)) {
82 | rudisha kweli
83 | }
84 | }
85 |
86 | grid[row][col] = 0
87 | }
88 |
89 | rudisha sikweli
90 | }
91 | andika()
92 | andika("----- PUZZLE TO SOLVE -----")
93 | printing(sudoku)
94 | kama (solveSudoku(sudoku, 0, 0)){
95 | andika()
96 | andika("--------- SOLUTION --------")
97 | printing(sudoku)
98 | andika()
99 | } sivyo {
100 | andika("imeshindikana")
101 | }
--------------------------------------------------------------------------------
/extensions/README.md:
--------------------------------------------------------------------------------
1 | # Nuru Extensions For Various Editors
2 |
3 | ## [VSCODE](./vscode/)
4 |
5 | Nuru syntax highlighting on VSCode
6 |
7 | ## [VIM](./vim)
8 |
9 | The file contained herein has a basic syntax highlight for vim.
10 | The file should be saved in `$HOME/.vim/syntax/nuru.vim`.
11 | You should add the following line to your `.vimrc` or the appropriate location:
12 |
13 | ```vim
14 | au BufRead,BufNewFile *.nr set filetype=nuru
15 | ```
16 |
17 | Only basic syntax highlighting is provided by the script.
18 |
--------------------------------------------------------------------------------
/extensions/vim/syntax/nuru.vim:
--------------------------------------------------------------------------------
1 | " Sintaksia ya nuru kwenye programu ya "vim"
2 | " Lugha: Nuru
3 |
4 | " Maneno tengwa
5 | syntax keyword nuruKeyword unda pakeji rudisha vunja endelea tupu
6 | syntax keyword nuruType fanya
7 | syntax keyword nuruBool kweli sikweli
8 | syntax keyword nuruConditional kama sivyo au
9 | syntax match nuruComparision /[!\|<>]/
10 | syntax keyword nuruLoop ktk while badili
11 | syntax keyword nuruLabel ikiwa kawaida
12 |
13 | " Nambari
14 | syntax match nuruInt '[+-]\d\+' contained display
15 | syntax match nuruFloat '[+-]\d+\.\d*' contained display
16 |
17 | " Viendeshaji
18 | syntax match nuruAssignment '='
19 | syntax match nuruLogicalOP /[\&!|]/
20 |
21 | " Vitendakazi
22 | syntax keyword nuruFunction andika aina jaza fungua
23 |
24 | " Tungo
25 | syntax region nuruString start=/"/ skip=/\\"/ end=/"/
26 | syntax region nuruString start=/'/ skip=/\\'/ end=/'/
27 |
28 | " Maoni
29 | syntax match nuruComment "//.*"
30 | syntax region nuruComment start="/\*" end="\*/"
31 |
32 | " Fafanua sintaksia
33 | let b:current_syntax = "nuru"
34 |
35 | highlight def link nuruComment Comment
36 | highlight def link nuruBool Boolean
37 | highlight def link nuruFunction Function
38 | highlight def link nuruComparision Conditional
39 | highlight def link nuruConditional Conditional
40 | highlight def link nuruKeyword Keyword
41 | highlight def link nuruString String
42 | highlight def link nuruVariable Identifier
43 | highlight def link nuruLoop Repeat
44 | highlight def link nuruInt Number
45 | highlight def link nuruFloat Float
46 | highlight def link nuruAssignment Operator
47 | highlight def link nuruLogicalOP Operator
48 | highlight def link nuruAriOP Operator
49 | highlight def link nuruType Type
50 | highlight def link nuruLabel Label
51 |
52 |
--------------------------------------------------------------------------------
/extensions/vscode/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Change Log
2 |
3 | All notable changes to the "nuru" extension will be documented in this file.
4 |
5 | Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how to structure this file.
6 |
7 | ## [Unreleased]
8 |
9 | - Initial release
--------------------------------------------------------------------------------
/extensions/vscode/README.md:
--------------------------------------------------------------------------------
1 | # Nuru VSCode Extension
2 |
3 | This is a syntax highliting extension for Nuru on vscode. It detects `.nr` and `.sw` files.
4 |
5 | ## Screenshots
6 |
7 |
8 |
9 |
10 | ## How To Install
11 |
12 | ### Download From Market Place
13 |
14 | - Simply download the Nuru Extension from VSCode Market Place
15 |
16 | ### Windows
17 |
18 | - 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`
19 | - Restart VSCode
20 |
21 | ### Linux and MacOS
22 |
23 | - 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`
24 | - Restart VSCode
25 |
--------------------------------------------------------------------------------
/extensions/vscode/assets/screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NuruProgramming/Nuru/0805bb2df91dda4040be58160f8db114cc84764f/extensions/vscode/assets/screenshot.png
--------------------------------------------------------------------------------
/extensions/vscode/nuru/language-configuration.json:
--------------------------------------------------------------------------------
1 | {
2 | "comments": {
3 | // symbol used for single line comment. Remove this entry if your language does not support line comments
4 | "lineComment": "//",
5 | // symbols used for start and end a block comment. Remove this entry if your language does not support block comments
6 | "blockComment": [
7 | "/*",
8 | "*/"
9 | ]
10 | },
11 | // symbols used as brackets
12 | "brackets": [
13 | [
14 | "{",
15 | "}"
16 | ],
17 | [
18 | "[",
19 | "]"
20 | ],
21 | [
22 | "(",
23 | ")"
24 | ]
25 | ],
26 | // symbols that are auto closed when typing
27 | "autoClosingPairs": [
28 | [
29 | "{",
30 | "}"
31 | ],
32 | [
33 | "[",
34 | "]"
35 | ],
36 | [
37 | "(",
38 | ")"
39 | ],
40 | [
41 | "\"",
42 | "\""
43 | ],
44 | [
45 | "'",
46 | "'"
47 | ]
48 | ],
49 | // symbols that can be used to surround a selection
50 | "surroundingPairs": [
51 | [
52 | "{",
53 | "}"
54 | ],
55 | [
56 | "[",
57 | "]"
58 | ],
59 | [
60 | "(",
61 | ")"
62 | ],
63 | [
64 | "\"",
65 | "\""
66 | ],
67 | [
68 | "'",
69 | "'"
70 | ]
71 | ]
72 | }
--------------------------------------------------------------------------------
/extensions/vscode/nuru/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "nuru",
3 | "displayName": "Nuru",
4 | "description": "Nuru Programming Language",
5 | "version": "0.0.1",
6 | "engines": {
7 | "vscode": "^1.74.0"
8 | },
9 | "categories": [
10 | "Programming Languages"
11 | ],
12 | "contributes": {
13 | "languages": [
14 | {
15 | "id": "nuru",
16 | "aliases": [
17 | "Nuru Programming Language",
18 | "nuru"
19 | ],
20 | "extensions": [
21 | ".nr",
22 | ".sw"
23 | ],
24 | "configuration": "./language-configuration.json"
25 | }
26 | ],
27 | "grammars": [
28 | {
29 | "language": "nuru",
30 | "scopeName": "source.nr",
31 | "path": "./syntaxes/nuru.tmLanguage.json"
32 | }
33 | ]
34 | }
35 | }
--------------------------------------------------------------------------------
/extensions/vscode/nuru/syntaxes/nuru.tmLanguage.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://raw.githubusercontent.com/martinring/tmlanguage/master/tmlanguage.json",
3 | "name": "Nuru Programming Language",
4 | "scopeName": "source.nr",
5 | "fileTypes": [
6 | "nr"
7 | ],
8 | "patterns": [
9 | {
10 | "include": "#linecomments"
11 | },
12 | {
13 | "include": "#blockcomments"
14 | },
15 | {
16 | "include": "#operators"
17 | },
18 | {
19 | "include": "#punctuation"
20 | },
21 | {
22 | "include": "#numbers"
23 | },
24 | {
25 | "include": "#constant"
26 | },
27 | {
28 | "include": "#keywords"
29 | },
30 | {
31 | "include": "#strings"
32 | },
33 | {
34 | "include": "#identifiers"
35 | }
36 | ],
37 | "repository": {
38 | "linecomments": {
39 | "name": "comment.line.double-slash.nuru",
40 | "match": "(//).*$\n?",
41 | "captures": {
42 | "1": {
43 | "name": "punctuation.definition.comment.nuru"
44 | }
45 | }
46 | },
47 | "blockcomments": {
48 | "name": "comment.block.nuru",
49 | "begin": "/\\*",
50 | "end": "\\*/",
51 | "captures": {
52 | "0": {
53 | "name": "punctuation.definition.comment.nuru"
54 | }
55 | }
56 | },
57 | "numbers": {
58 | "name": "constant.numeric.nuru",
59 | "match": "\\b[0-9]+(\\.[0-9]+)?\\b"
60 | },
61 | "constant": {
62 | "name": "constant.language.nuru",
63 | "match": "\\b(kweli|sikweli)\\b"
64 | },
65 | "operators": {
66 | "patterns": [
67 | {
68 | "name": "keyword.operator.arithmetic.nuru",
69 | "match": "\\b(\\+|\\-|%|\\*|\\/|\\^)\\b"
70 | },
71 | {
72 | "name": "keyword.operator.logical.nuru",
73 | "match": "\\b(==|<=|>=|<|>|&&|\\|\\|)\\b"
74 | },
75 | {
76 | "name": "keyword.operator.assignment.nuru",
77 | "match": "\\b(=|:)\\b"
78 | },
79 | {
80 | "name": "punctuation.accessor.nuru",
81 | "match": "\\."
82 | }
83 | ]
84 | },
85 | "punctuation": {
86 | "patterns": [
87 | {
88 | "name": "punctuation.separator",
89 | "match": ","
90 | },
91 | {
92 | "include": "#groups"
93 | }
94 | ]
95 | },
96 | "keywords": {
97 | "patterns": [
98 | {
99 | "name": "storage.type.function.nuru",
100 | "match": "\\b(unda|andika|idadi|jumla|yamwisho|sukuma|jaza|aina|fungua)\\b"
101 | },
102 | {
103 | "name": "storage.type.nuru",
104 | "match": "\\bfanya\\b"
105 | },
106 | {
107 | "name": "keyword.control.nuru",
108 | "match": "\\b(kama|au|sivyo|wakati|rudisha|vunja|endelea|tupu|ktk|kwa|badili|ikiwa|kawaida|tumia)\\b"
109 | },
110 | {
111 | "name": "support.function.nuru",
112 | "match": "\\b(os|muda)\\b"
113 | }
114 | ]
115 | },
116 | "identifiers": {
117 | "patterns": [
118 | {
119 | "name": "meta.functioncall.nuru",
120 | "match": "\\b([_A-Za-z][_A-Za-z0-9]*)\\b(?=\\()",
121 | "captures": {
122 | "1": {
123 | "name": "entity.name.function.nuru"
124 | }
125 | }
126 | }
127 | ]
128 | },
129 | "strings": {
130 | "patterns": [
131 | {
132 | "name": "string.quoted.double.nuru",
133 | "begin": "\"",
134 | "end": "\"",
135 | "patterns": [
136 | {
137 | "name": "constant.character.escape.nuru",
138 | "match": "\\\\."
139 | }
140 | ]
141 | },
142 | {
143 | "name": "string.quoted.single.nuru",
144 | "begin": "\\'",
145 | "end": "\\'",
146 | "patterns": [
147 | {
148 | "name": "constant.character.escape.nuru",
149 | "match": "\\\\."
150 | }
151 | ]
152 | }
153 | ]
154 | }
155 | }
156 | }
--------------------------------------------------------------------------------
/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/NuruProgramming/Nuru
2 |
3 | go 1.18
4 |
5 | require (
6 | github.com/AvicennaJr/GoPrompt v0.0.0-20230411215003-be2316d88e2d
7 | github.com/charmbracelet/bubbles v0.15.0
8 | github.com/charmbracelet/bubbletea v0.23.2
9 | github.com/charmbracelet/glamour v0.6.0
10 | github.com/charmbracelet/lipgloss v0.7.1
11 | github.com/lrstanley/bubblezone v0.0.0-20230303230241-08f906ff62a9
12 | )
13 |
14 | require (
15 | github.com/alecthomas/chroma v0.10.0 // indirect
16 | github.com/atotto/clipboard v0.1.4 // indirect
17 | github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
18 | github.com/aymerick/douceur v0.2.0 // indirect
19 | github.com/containerd/console v1.0.3 // indirect
20 | github.com/dlclark/regexp2 v1.4.0 // indirect
21 | github.com/gorilla/css v1.0.0 // indirect
22 | github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
23 | github.com/mattn/go-colorable v0.1.7 // indirect
24 | github.com/mattn/go-isatty v0.0.18 // indirect
25 | github.com/mattn/go-localereader v0.0.1 // indirect
26 | github.com/mattn/go-runewidth v0.0.14 // indirect
27 | github.com/mattn/go-tty v0.0.3 // indirect
28 | github.com/microcosm-cc/bluemonday v1.0.21 // indirect
29 | github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect
30 | github.com/muesli/cancelreader v0.2.2 // indirect
31 | github.com/muesli/reflow v0.3.0 // indirect
32 | github.com/muesli/termenv v0.15.1 // indirect
33 | github.com/olekukonko/tablewriter v0.0.5 // indirect
34 | github.com/pkg/term v1.2.0-beta.2 // indirect
35 | github.com/rivo/uniseg v0.4.4 // indirect
36 | github.com/sahilm/fuzzy v0.1.0 // indirect
37 | github.com/yuin/goldmark v1.5.2 // indirect
38 | github.com/yuin/goldmark-emoji v1.0.1 // indirect
39 | golang.org/x/net v0.0.0-20221002022538-bcab6841153b // indirect
40 | golang.org/x/sync v0.1.0 // indirect
41 | golang.org/x/sys v0.7.0 // indirect
42 | golang.org/x/term v0.7.0 // indirect
43 | golang.org/x/text v0.9.0 // indirect
44 | )
45 |
--------------------------------------------------------------------------------
/gotest:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NuruProgramming/Nuru/0805bb2df91dda4040be58160f8db114cc84764f/gotest
--------------------------------------------------------------------------------
/lexer/lexer_test.go:
--------------------------------------------------------------------------------
1 | package lexer
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/NuruProgramming/Nuru/token"
7 | )
8 |
9 | func TestNextToken(t *testing.T) {
10 | input := `
11 | // Testing kama lex luther iko sawa
12 | fanya tano = 5;
13 | fanya kumi = 10;
14 |
15 | fanya jumla = unda(x, y){
16 | x + y;
17 | };
18 |
19 | fanya jibu = jumla(tano, kumi);
20 |
21 | !-/5;
22 | 5 < 10 > 5;
23 |
24 | kama (5 < 10) {
25 | rudisha kweli;
26 | } sivyo {
27 | rudisha sikweli;
28 | }
29 |
30 | 10 == 10;
31 | 10 != 9; // Hii ni comment
32 | // Comment nyingine
33 |
34 | /*
35 | multiline comment
36 | */
37 |
38 | /* multiline comment number twooooooooooo */
39 | 5
40 | "bangi"
41 | "ba ngi"
42 | [1, 2];
43 | {"mambo": "vipi"}
44 | . // test dot
45 | tumia muda
46 |
47 | badili (a) {
48 | ikiwa 2 {
49 | andika(2)
50 | }
51 | kawaida {
52 | andika(0)
53 | }
54 | }
55 |
56 | tupu
57 |
58 | kwa i, v ktk j`
59 |
60 | tests := []struct {
61 | expectedType token.TokenType
62 | expectedLiteral string
63 | }{
64 | {token.LET, "fanya"},
65 | {token.IDENT, "tano"},
66 | {token.ASSIGN, "="},
67 | {token.INT, "5"},
68 | {token.SEMICOLON, ";"},
69 | {token.LET, "fanya"},
70 | {token.IDENT, "kumi"},
71 | {token.ASSIGN, "="},
72 | {token.INT, "10"},
73 | {token.SEMICOLON, ";"},
74 | {token.LET, "fanya"},
75 | {token.IDENT, "jumla"},
76 | {token.ASSIGN, "="},
77 | {token.FUNCTION, "unda"},
78 | {token.LPAREN, "("},
79 | {token.IDENT, "x"},
80 | {token.COMMA, ","},
81 | {token.IDENT, "y"},
82 | {token.RPAREN, ")"},
83 | {token.LBRACE, "{"},
84 | {token.IDENT, "x"},
85 | {token.PLUS, "+"},
86 | {token.IDENT, "y"},
87 | {token.SEMICOLON, ";"},
88 | {token.RBRACE, "}"},
89 | {token.SEMICOLON, ";"},
90 | {token.LET, "fanya"},
91 | {token.IDENT, "jibu"},
92 | {token.ASSIGN, "="},
93 | {token.IDENT, "jumla"},
94 | {token.LPAREN, "("},
95 | {token.IDENT, "tano"},
96 | {token.COMMA, ","},
97 | {token.IDENT, "kumi"},
98 | {token.RPAREN, ")"},
99 | {token.SEMICOLON, ";"},
100 | {token.BANG, "!"},
101 | {token.MINUS, "-"},
102 | {token.SLASH, "/"},
103 | {token.INT, "5"},
104 | {token.SEMICOLON, ";"},
105 | {token.INT, "5"},
106 | {token.LT, "<"},
107 | {token.INT, "10"},
108 | {token.GT, ">"},
109 | {token.INT, "5"},
110 | {token.SEMICOLON, ";"},
111 | {token.IF, "kama"},
112 | {token.LPAREN, "("},
113 | {token.INT, "5"},
114 | {token.LT, "<"},
115 | {token.INT, "10"},
116 | {token.RPAREN, ")"},
117 | {token.LBRACE, "{"},
118 | {token.RETURN, "rudisha"},
119 | {token.TRUE, "kweli"},
120 | {token.SEMICOLON, ";"},
121 | {token.RBRACE, "}"},
122 | {token.ELSE, "sivyo"},
123 | {token.LBRACE, "{"},
124 | {token.RETURN, "rudisha"},
125 | {token.FALSE, "sikweli"},
126 | {token.SEMICOLON, ";"},
127 | {token.RBRACE, "}"},
128 | {token.INT, "10"},
129 | {token.EQ, "=="},
130 | {token.INT, "10"},
131 | {token.SEMICOLON, ";"},
132 | {token.INT, "10"},
133 | {token.NOT_EQ, "!="},
134 | {token.INT, "9"},
135 | {token.SEMICOLON, ";"},
136 | {token.INT, "5"},
137 | {token.STRING, "bangi"},
138 | {token.STRING, "ba ngi"},
139 | {token.LBRACKET, "["},
140 | {token.INT, "1"},
141 | {token.COMMA, ","},
142 | {token.INT, "2"},
143 | {token.RBRACKET, "]"},
144 | {token.SEMICOLON, ";"},
145 | {token.LBRACE, "{"},
146 | {token.STRING, "mambo"},
147 | {token.COLON, ":"},
148 | {token.STRING, "vipi"},
149 | {token.RBRACE, "}"},
150 | {token.DOT, "."},
151 | {token.IMPORT, "tumia"},
152 | {token.IDENT, "muda"},
153 | {token.SWITCH, "badili"},
154 | {token.LPAREN, "("},
155 | {token.IDENT, "a"},
156 | {token.RPAREN, ")"},
157 | {token.LBRACE, "{"},
158 | {token.CASE, "ikiwa"},
159 | {token.INT, "2"},
160 | {token.LBRACE, "{"},
161 | {token.IDENT, "andika"},
162 | {token.LPAREN, "("},
163 | {token.INT, "2"},
164 | {token.RPAREN, ")"},
165 | {token.RBRACE, "}"},
166 | {token.DEFAULT, "kawaida"},
167 | {token.LBRACE, "{"},
168 | {token.IDENT, "andika"},
169 | {token.LPAREN, "("},
170 | {token.INT, "0"},
171 | {token.RPAREN, ")"},
172 | {token.RBRACE, "}"},
173 | {token.RBRACE, "}"},
174 | {token.NULL, "tupu"},
175 | {token.FOR, "kwa"},
176 | {token.IDENT, "i"},
177 | {token.COMMA, ","},
178 | {token.IDENT, "v"},
179 | {token.IN, "ktk"},
180 | {token.IDENT, "j"},
181 | {token.EOF, ""},
182 | }
183 |
184 | l := New(input)
185 |
186 | for i, tt := range tests {
187 | tok := l.NextToken()
188 |
189 | if tok.Type != tt.expectedType {
190 | t.Fatalf("tests[%d] - tokentype wrong. expected=%q, got=%q",
191 | i, tt.expectedType, tok.Type)
192 | }
193 |
194 | if tok.Literal != tt.expectedLiteral {
195 | t.Fatalf("tests[%d] - literal wrong. expected=%q, got=%q",
196 | i, tt.expectedLiteral, tok.Literal)
197 | }
198 | }
199 | }
200 |
--------------------------------------------------------------------------------
/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "os"
6 | "strings"
7 |
8 | "github.com/NuruProgramming/Nuru/repl"
9 | "github.com/NuruProgramming/Nuru/styles"
10 | "github.com/charmbracelet/lipgloss"
11 | )
12 |
13 | var (
14 | Title = styles.TitleStyle.
15 | Render(`
16 | █░░ █░█ █▀▀ █░█ ▄▀█ █▄█ ▄▀█ █▄░█ █░█ █▀█ █░█
17 | █▄▄ █▄█ █▄█ █▀█ █▀█ ░█░ █▀█ █░▀█ █▄█ █▀▄ █▄█`)
18 | Version = styles.VersionStyle.Render("v0.5.18")
19 | Author = styles.AuthorStyle.Render("by Nuru Org")
20 | NewLogo = lipgloss.JoinVertical(lipgloss.Center, Title, lipgloss.JoinHorizontal(lipgloss.Center, Author, " | ", Version))
21 | Help = styles.HelpStyle.Italic(false).Render(fmt.Sprintf(`💡 Namna ya kutumia Nuru:
22 | %s: Kuanza programu ya Nuru
23 | %s: Kuendesha faili la Nuru
24 | %s: Kusoma nyaraka za Nuru
25 | %s: Kufahamu toleo la Nuru
26 | `,
27 | styles.HelpStyle.Bold(true).Render("nuru"),
28 | styles.HelpStyle.Bold(true).Render("nuru jinaLaFile.nr"),
29 | styles.HelpStyle.Bold(true).Render("nuru --nyaraka"),
30 | styles.HelpStyle.Bold(true).Render("nuru --toleo")))
31 | )
32 |
33 | func main() {
34 |
35 | args := os.Args
36 | if len(args) < 2 {
37 |
38 | help := styles.HelpStyle.Render("💡 Tumia exit() au toka() kuondoka")
39 | fmt.Println(lipgloss.JoinVertical(lipgloss.Left, NewLogo, "\n", help))
40 | repl.Start()
41 | return
42 | }
43 |
44 | if len(args) == 2 {
45 | switch args[1] {
46 | case "msaada", "-msaada", "--msaada", "help", "-help", "--help", "-h":
47 | fmt.Println(Help)
48 | case "version", "-version", "--version", "-v", "v", "--toleo", "-toleo":
49 | fmt.Println(NewLogo)
50 | case "-docs", "--docs", "-nyaraka", "--nyaraka":
51 | repl.Docs()
52 | default:
53 | file := args[1]
54 |
55 | if strings.HasSuffix(file, "nr") || strings.HasSuffix(file, ".sw") {
56 | contents, err := os.ReadFile(file)
57 | if err != nil {
58 | fmt.Println(styles.ErrorStyle.Render("Error: Nuru imeshindwa kusoma faili: ", args[1]))
59 | os.Exit(1)
60 | }
61 |
62 | repl.Read(string(contents))
63 | } else {
64 | fmt.Println(styles.ErrorStyle.Render("'"+file+"'", "sii faili sahihi. Tumia faili la '.nr' au '.sw'"))
65 | os.Exit(1)
66 | }
67 | }
68 | } else {
69 | fmt.Println(styles.ErrorStyle.Render("Error: Operesheni imeshindikana boss."))
70 | fmt.Println(Help)
71 | os.Exit(1)
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/module/json.go:
--------------------------------------------------------------------------------
1 | package module
2 |
3 | import (
4 | "encoding/json"
5 |
6 | "github.com/NuruProgramming/Nuru/object"
7 | )
8 |
9 | var JsonFunctions = map[string]object.ModuleFunction{}
10 |
11 | func init() {
12 | JsonFunctions["dikodi"] = decode
13 | JsonFunctions["enkodi"] = encode
14 | }
15 |
16 | func decode(args []object.Object, defs map[string]object.Object) object.Object {
17 | if len(defs) != 0 {
18 | return &object.Error{Message: "Hoja hii hairuhusiwi"}
19 | }
20 | if len(args) != 1 {
21 | return &object.Error{Message: "Tunahitaji hoja moja tu"}
22 | }
23 |
24 | if args[0].Type() != object.STRING_OBJ {
25 | return &object.Error{Message: "Hoja lazima iwe neno"}
26 | }
27 |
28 | var i interface{}
29 |
30 | input := args[0].(*object.String).Value
31 | err := json.Unmarshal([]byte(input), &i)
32 | if err != nil {
33 | return &object.Error{Message: "Hii data sio jsoni"}
34 | }
35 |
36 | return convertWhateverToObject(i)
37 | }
38 |
39 | func convertWhateverToObject(i interface{}) object.Object {
40 | switch v := i.(type) {
41 | case map[string]interface{}:
42 | dict := &object.Dict{}
43 | dict.Pairs = make(map[object.HashKey]object.DictPair)
44 |
45 | for k, v := range v {
46 | pair := object.DictPair{
47 | Key: &object.String{Value: k},
48 | Value: convertWhateverToObject(v),
49 | }
50 | dict.Pairs[pair.Key.(object.Hashable).HashKey()] = pair
51 | }
52 |
53 | return dict
54 | case []interface{}:
55 | list := &object.Array{}
56 | for _, e := range v {
57 | list.Elements = append(list.Elements, convertWhateverToObject(e))
58 | }
59 |
60 | return list
61 | case string:
62 | return &object.String{Value: v}
63 | case int64:
64 | return &object.Integer{Value: v}
65 | case float64:
66 | return &object.Float{Value: v}
67 | case bool:
68 | if v {
69 | return &object.Boolean{Value: true}
70 | } else {
71 | return &object.Boolean{Value: false}
72 | }
73 | }
74 | return &object.Null{}
75 | }
76 |
77 | func encode(args []object.Object, defs map[string]object.Object) object.Object {
78 | if len(defs) != 0 {
79 | return &object.Error{Message: "Hoja hii hairuhusiwi"}
80 | }
81 |
82 | input := args[0]
83 | i := convertObjectToWhatever(input)
84 | data, err := json.Marshal(i)
85 |
86 | if err != nil {
87 | return &object.Error{Message: "Siwezi kubadilisha data hii kuwa jsoni"}
88 | }
89 |
90 | return &object.String{Value: string(data)}
91 | }
92 |
93 | func convertObjectToWhatever(obj object.Object) interface{} {
94 | switch v := obj.(type) {
95 | case *object.Dict:
96 | m := make(map[string]interface{})
97 | for _, pair := range v.Pairs {
98 | key := pair.Key.(*object.String).Value
99 | m[key] = convertObjectToWhatever(pair.Value)
100 | }
101 | return m
102 | case *object.Array:
103 | list := make([]interface{}, len(v.Elements))
104 | for i, e := range v.Elements {
105 | list[i] = convertObjectToWhatever(e)
106 | }
107 | return list
108 | case *object.String:
109 | return v.Value
110 | case *object.Integer:
111 | return v.Value
112 | case *object.Float:
113 | return v.Value
114 | case *object.Boolean:
115 | return v.Value
116 | case *object.Null:
117 | return nil
118 | }
119 | return nil
120 | }
121 |
--------------------------------------------------------------------------------
/module/module.go:
--------------------------------------------------------------------------------
1 | package module
2 |
3 | import "github.com/NuruProgramming/Nuru/object"
4 |
5 | var Mapper = map[string]*object.Module{}
6 |
7 | func init() {
8 | Mapper["os"] = &object.Module{Name: "os", Functions: OsFunctions}
9 | Mapper["muda"] = &object.Module{Name: "time", Functions: TimeFunctions}
10 | Mapper["mtandao"] = &object.Module{Name: "net", Functions: NetFunctions}
11 | Mapper["jsoni"] = &object.Module{Name: "json", Functions: JsonFunctions}
12 | Mapper["hisabati"] = &object.Module{Name: "hisabati", Functions: MathFunctions}
13 | }
14 |
--------------------------------------------------------------------------------
/module/net.go:
--------------------------------------------------------------------------------
1 | package module
2 |
3 | import (
4 | "bytes"
5 | "encoding/json"
6 | "io/ioutil"
7 | "net/http"
8 |
9 | "github.com/NuruProgramming/Nuru/object"
10 | )
11 |
12 | var NetFunctions = map[string]object.ModuleFunction{}
13 |
14 | func init() {
15 | NetFunctions["peruzi"] = getRequest
16 | NetFunctions["tuma"] = postRequest
17 | }
18 |
19 | func getRequest(args []object.Object, defs map[string]object.Object) object.Object {
20 |
21 | if len(defs) != 0 {
22 | var url *object.String
23 | var headers, params *object.Dict
24 | for k, v := range defs {
25 | switch k {
26 | case "yuareli":
27 | strUrl, ok := v.(*object.String)
28 | if !ok {
29 | return &object.Error{Message: "Yuareli iwe neno"}
30 | }
31 | url = strUrl
32 | case "vichwa":
33 | dictHead, ok := v.(*object.Dict)
34 | if !ok {
35 | return &object.Error{Message: "Vichwa lazima viwe kamusi"}
36 | }
37 | headers = dictHead
38 | case "mwili":
39 | dictHead, ok := v.(*object.Dict)
40 | if !ok {
41 | return &object.Error{Message: "Mwili lazima iwe kamusi"}
42 | }
43 | params = dictHead
44 | default:
45 | return &object.Error{Message: "Hoja si sahihi. Tumia yuareli na vichwa."}
46 | }
47 | }
48 | if url.Value == "" {
49 | return &object.Error{Message: "Yuareli ni lazima"}
50 | }
51 |
52 | var responseBody *bytes.Buffer
53 | if params != nil {
54 | booty := convertObjectToWhatever(params)
55 |
56 | jsonBody, err := json.Marshal(booty)
57 |
58 | if err != nil {
59 | return &object.Error{Message: "Huku format query yako vizuri."}
60 | }
61 |
62 | responseBody = bytes.NewBuffer(jsonBody)
63 | }
64 |
65 | var req *http.Request
66 | var err error
67 | if responseBody != nil {
68 | req, err = http.NewRequest("GET", url.Value, responseBody)
69 | } else {
70 | req, err = http.NewRequest("GET", url.Value, nil)
71 | }
72 | if err != nil {
73 | return &object.Error{Message: "Tumeshindwa kufanya request"}
74 | }
75 |
76 | if headers != nil {
77 | for _, val := range headers.Pairs {
78 | req.Header.Set(val.Key.Inspect(), val.Value.Inspect())
79 | }
80 | }
81 | client := &http.Client{}
82 |
83 | resp, err := client.Do(req)
84 |
85 | if err != nil {
86 | return &object.Error{Message: "Tumeshindwa kutuma request."}
87 | }
88 | defer resp.Body.Close()
89 | respBody, err := ioutil.ReadAll(resp.Body)
90 | if err != nil {
91 | return &object.Error{Message: "Tumeshindwa kusoma majibu."}
92 | }
93 |
94 | return &object.String{Value: string(respBody)}
95 |
96 | }
97 |
98 | if len(args) == 1 {
99 | url, ok := args[0].(*object.String)
100 | if !ok {
101 | return &object.Error{Message: "Yuareli lazima iwe neno"}
102 | }
103 | req, err := http.NewRequest("GET", url.Value, nil)
104 | if err != nil {
105 | return &object.Error{Message: "Tumeshindwa kufanya request"}
106 | }
107 |
108 | client := &http.Client{}
109 |
110 | resp, err := client.Do(req)
111 |
112 | if err != nil {
113 | return &object.Error{Message: "Tumeshindwa kutuma request."}
114 | }
115 | defer resp.Body.Close()
116 | respBody, err := ioutil.ReadAll(resp.Body)
117 | if err != nil {
118 | return &object.Error{Message: "Tumeshindwa kusoma majibu."}
119 | }
120 |
121 | return &object.String{Value: string(respBody)}
122 | }
123 | return &object.Error{Message: "Hoja si sahihi. Tumia yuareli na vichwa."}
124 | }
125 |
126 | func postRequest(args []object.Object, defs map[string]object.Object) object.Object {
127 | if len(defs) != 0 {
128 | var url *object.String
129 | var headers, params *object.Dict
130 | for k, v := range defs {
131 | switch k {
132 | case "yuareli":
133 | strUrl, ok := v.(*object.String)
134 | if !ok {
135 | return &object.Error{Message: "Yuareli iwe neno"}
136 | }
137 | url = strUrl
138 | case "vichwa":
139 | dictHead, ok := v.(*object.Dict)
140 | if !ok {
141 | return &object.Error{Message: "Vichwa lazima viwe kamusi"}
142 | }
143 | headers = dictHead
144 | case "mwili":
145 | dictHead, ok := v.(*object.Dict)
146 | if !ok {
147 | return &object.Error{Message: "Mwili lazima iwe kamusi"}
148 | }
149 | params = dictHead
150 | default:
151 | return &object.Error{Message: "Hoja si sahihi. Tumia yuareli na vichwa."}
152 | }
153 | }
154 | if url.Value == "" {
155 | return &object.Error{Message: "Yuareli ni lazima"}
156 | }
157 | var responseBody *bytes.Buffer
158 | if params != nil {
159 | booty := convertObjectToWhatever(params)
160 |
161 | jsonBody, err := json.Marshal(booty)
162 |
163 | if err != nil {
164 | return &object.Error{Message: "Huku format query yako vizuri."}
165 | }
166 |
167 | responseBody = bytes.NewBuffer(jsonBody)
168 | }
169 | var req *http.Request
170 | var err error
171 | if responseBody != nil {
172 | req, err = http.NewRequest("POST", url.Value, responseBody)
173 | } else {
174 | req, err = http.NewRequest("POST", url.Value, nil)
175 | }
176 | if err != nil {
177 | return &object.Error{Message: "Tumeshindwa kufanya request"}
178 | }
179 | if headers != nil {
180 | for _, val := range headers.Pairs {
181 | req.Header.Set(val.Key.Inspect(), val.Value.Inspect())
182 | }
183 | }
184 | req.Header.Add("Content-Type", "application/json")
185 |
186 | client := &http.Client{}
187 |
188 | resp, err := client.Do(req)
189 |
190 | if err != nil {
191 | return &object.Error{Message: "Tumeshindwa kutuma request."}
192 | }
193 | defer resp.Body.Close()
194 | respBody, err := ioutil.ReadAll(resp.Body)
195 | if err != nil {
196 | return &object.Error{Message: "Tumeshindwa kusoma majibu."}
197 | }
198 | return &object.String{Value: string(respBody)}
199 | }
200 | return &object.Error{Message: "Hoja si sahihi. Tumia yuareli na vichwa."}
201 | }
202 |
--------------------------------------------------------------------------------
/module/os.go:
--------------------------------------------------------------------------------
1 | package module
2 |
3 | import (
4 | "os"
5 | "os/exec"
6 | "strings"
7 |
8 | "github.com/NuruProgramming/Nuru/object"
9 | )
10 |
11 | var OsFunctions = map[string]object.ModuleFunction{}
12 |
13 | func init() {
14 | OsFunctions["toka"] = exit
15 | OsFunctions["kimbiza"] = run
16 | }
17 |
18 | func exit(args []object.Object, defs map[string]object.Object) object.Object {
19 | if len(args) > 1 {
20 | return &object.Error{Message: "Hoja sii sahihi"}
21 | }
22 |
23 | if len(args) == 1 {
24 | status, ok := args[0].(*object.Integer)
25 | if !ok {
26 | return &object.Error{Message: "Hoja sii namba"}
27 | }
28 | os.Exit(int(status.Value))
29 | return nil
30 | }
31 |
32 | os.Exit(0)
33 |
34 | return nil
35 | }
36 |
37 | func run(args []object.Object, defs map[string]object.Object) object.Object {
38 | if len(args) != 1 {
39 | return &object.Error{Message: "Idadi ya hoja sii sahihi"}
40 | }
41 |
42 | cmd, ok := args[0].(*object.String)
43 | if !ok {
44 | return &object.Error{Message: "Hoja lazima iwe neno"}
45 | }
46 | cmdMain := cmd.Value
47 | cmdArgs := strings.Split(cmdMain, " ")
48 | cmdArgs = cmdArgs[1:]
49 |
50 | out, err := exec.Command(cmdMain, cmdArgs...).Output()
51 | if err != nil {
52 | return &object.Error{Message: "Tumeshindwa kukimbiza komandi"}
53 | }
54 |
55 | return &object.String{Value: string(out)}
56 | }
57 |
--------------------------------------------------------------------------------
/module/time.go:
--------------------------------------------------------------------------------
1 | package module
2 |
3 | import (
4 | "fmt"
5 | "strconv"
6 | "time"
7 |
8 | "github.com/NuruProgramming/Nuru/object"
9 | )
10 |
11 | var TimeFunctions = map[string]object.ModuleFunction{}
12 |
13 | func init() {
14 | TimeFunctions["hasahivi"] = now
15 | TimeFunctions["lala"] = sleep
16 | TimeFunctions["tangu"] = since
17 | TimeFunctions["leo"] = today
18 | TimeFunctions["baada_ya"] = after
19 | TimeFunctions["tofauti"] = diff
20 | TimeFunctions["ongeza"] = addTime
21 | }
22 |
23 | func now(args []object.Object, defs map[string]object.Object) object.Object {
24 | if len(args) != 0 || len(defs) != 0 {
25 | return &object.Error{Message: "hatuhitaji hoja kwenye hasahivi"}
26 | }
27 |
28 | tn := time.Now()
29 | time_string := tn.Format("15:04:05 02-01-2006")
30 |
31 | return &object.Time{TimeValue: time_string}
32 | }
33 |
34 | func sleep(args []object.Object, defs map[string]object.Object) object.Object {
35 | if len(defs) != 0 {
36 | return &object.Error{Message: "Hoja hii hairuhusiwi"}
37 | }
38 | if len(args) != 1 {
39 | return &object.Error{Message: "tunahitaji hoja moja tu"}
40 | }
41 |
42 | objvalue := args[0].Inspect()
43 | inttime, err := strconv.Atoi(objvalue)
44 |
45 | if err != nil {
46 | return &object.Error{Message: "namba tu zinaruhusiwa kwenye hoja"}
47 | }
48 |
49 | time.Sleep(time.Duration(inttime) * time.Second)
50 |
51 | return nil
52 | }
53 |
54 | func since(args []object.Object, defs map[string]object.Object) object.Object {
55 | if len(defs) != 0 {
56 | return &object.Error{Message: "Hoja hii hairuhusiwi"}
57 | }
58 | if len(args) != 1 {
59 | return &object.Error{Message: "tunahitaji hoja moja tu"}
60 | }
61 |
62 | var (
63 | t time.Time
64 | err error
65 | )
66 |
67 | switch m := args[0].(type) {
68 | case *object.Time:
69 | t, _ = time.Parse("15:04:05 02-01-2006", m.TimeValue)
70 | case *object.String:
71 | t, err = time.Parse("15:04:05 02-01-2006", m.Value)
72 | if err != nil {
73 | return &object.Error{Message: fmt.Sprintf("Hoja %s sii sahihi", args[0].Inspect())}
74 | }
75 | default:
76 | return &object.Error{Message: fmt.Sprintf("Hoja %s sii sahihi", args[0].Inspect())}
77 | }
78 |
79 | current_time := time.Now().Format("15:04:05 02-01-2006")
80 | ct, _ := time.Parse("15:04:05 02-01-2006", current_time)
81 |
82 | diff := ct.Sub(t)
83 | durationInSeconds := diff.Seconds()
84 |
85 | return &object.Integer{Value: int64(durationInSeconds)}
86 | }
87 |
88 | func today(args []object.Object, defs map[string]object.Object) object.Object {
89 | if len(args) != 0 || len(defs) != 0 {
90 | return &object.Error{Message: "hatuhitaji hoja kwenye leo"}
91 | }
92 |
93 | dateStr := time.Now().Format("02-01-2006")
94 | return &object.String{Value: dateStr}
95 | }
96 |
97 | func after(args []object.Object, defs map[string]object.Object) object.Object {
98 | if len(defs) != 0 || len(args) != 1 {
99 | return &object.Error{Message: "tunahitaji hoja moja tu kwenye baada_ya"}
100 | }
101 |
102 | secondsStr := args[0].Inspect()
103 | seconds, err := strconv.Atoi(secondsStr)
104 | if err != nil {
105 | return &object.Error{Message: "hoja lazima iwe namba"}
106 | }
107 |
108 | future := time.Now().Add(time.Duration(seconds) * time.Second)
109 | return &object.Time{TimeValue: future.Format("15:04:05 02-01-2006")}
110 | }
111 |
112 | func diff(args []object.Object, defs map[string]object.Object) object.Object {
113 | if len(defs) != 0 || len(args) != 2 {
114 | return &object.Error{Message: "tunahitaji hoja mbili kwenye tofauti"}
115 | }
116 |
117 | parseTime := func(o object.Object) (time.Time, error) {
118 | switch v := o.(type) {
119 | case *object.Time:
120 | return time.Parse("15:04:05 02-01-2006", v.TimeValue)
121 | case *object.String:
122 | return time.Parse("15:04:05 02-01-2006", v.Value)
123 | default:
124 | return time.Time{}, fmt.Errorf("aina batili")
125 | }
126 | }
127 |
128 | t1, err1 := parseTime(args[0])
129 | t2, err2 := parseTime(args[1])
130 |
131 | if err1 != nil || err2 != nil {
132 | return &object.Error{Message: "tofauti inahitaji nyakati halali mbili"}
133 | }
134 |
135 | diff := t1.Sub(t2).Seconds()
136 | return &object.Integer{Value: int64(diff)}
137 | }
138 |
139 |
140 | func addTime(args []object.Object, defs map[string]object.Object) object.Object {
141 | if len(args) != 1 {
142 | return &object.Error{Message: "ongeza inahitaji wakati mmoja wa kuanzia"}
143 | }
144 |
145 | baseTimeObj := args[0]
146 | baseTime, err := func() (time.Time, error) {
147 | switch t := baseTimeObj.(type) {
148 | case *object.Time:
149 | return time.Parse("15:04:05 02-01-2006", t.TimeValue)
150 | case *object.String:
151 | return time.Parse("15:04:05 02-01-2006", t.Value)
152 | default:
153 | return time.Time{}, fmt.Errorf("aina ya wakati sio sahihi")
154 | }
155 | }()
156 | if err != nil {
157 | return &object.Error{Message: "wakati uliotolewa sio sahihi"}
158 | }
159 |
160 | secs := getInt(defs["sekunde"])
161 | mins := getInt(defs["dakika"])
162 | hours := getInt(defs["masaa"])
163 | days := getInt(defs["siku"])
164 | weeks := getInt(defs["wiki"])
165 | months := getInt(defs["miezi"])
166 | years := getInt(defs["miaka"])
167 |
168 | result := baseTime.
169 | Add(time.Second * time.Duration(secs)).
170 | Add(time.Minute * time.Duration(mins)).
171 | Add(time.Hour * time.Duration(hours)).
172 | AddDate(years, months, days+(weeks*7))
173 |
174 | return &object.Time{TimeValue: result.Format("15:04:05 02-01-2006")}
175 | }
176 |
177 | func getInt(obj object.Object) int {
178 | if obj == nil {
179 | return 0
180 | }
181 | switch o := obj.(type) {
182 | case *object.Integer:
183 | return int(o.Value)
184 | case *object.String:
185 | n, err := strconv.Atoi(o.Value)
186 | if err == nil {
187 | return n
188 | }
189 | }
190 | return 0
191 | }
192 |
--------------------------------------------------------------------------------
/object/array.go:
--------------------------------------------------------------------------------
1 | package object
2 |
3 | import (
4 | "bytes"
5 | "strings"
6 | )
7 |
8 | type Array struct {
9 | Elements []Object
10 | offset int
11 | }
12 |
13 | func (ao *Array) Type() ObjectType { return ARRAY_OBJ }
14 | func (ao *Array) Inspect() string {
15 | var out bytes.Buffer
16 |
17 | elements := []string{}
18 | if len(ao.Elements) != 0 {
19 | for _, e := range ao.Elements {
20 | if e.Inspect() != "" {
21 | elements = append(elements, e.Inspect())
22 | }
23 | }
24 | }
25 |
26 | out.WriteString("[")
27 | out.WriteString(strings.Join(elements, ", "))
28 | out.WriteString("]")
29 |
30 | return out.String()
31 | }
32 |
33 | func (ao *Array) Next() (Object, Object) {
34 | idx := ao.offset
35 | if len(ao.Elements) > idx {
36 | ao.offset = idx + 1
37 | return &Integer{Value: int64(idx)}, ao.Elements[idx]
38 | }
39 | return nil, nil
40 | }
41 |
42 | func (ao *Array) Reset() {
43 | ao.offset = 0
44 | }
45 |
46 | func (a *Array) Method(method string, args []Object) Object {
47 | switch method {
48 | case "idadi":
49 | return a.len(args)
50 | case "sukuma":
51 | return a.push(args)
52 | case "yamwisho":
53 | return a.last()
54 | case "unga":
55 | return a.join(args)
56 | case "chuja":
57 | return a.filter(args)
58 | case "tafuta":
59 | return a.find(args)
60 | default:
61 | return newError("Samahani, kiendesha hiki hakitumiki na tungo (Neno)")
62 | }
63 | }
64 |
65 | func (a *Array) len(args []Object) Object {
66 | if len(args) != 0 {
67 | return newError("Samahani, tunahitaji Hoja 0, wewe umeweka %d", len(args))
68 | }
69 | return &Integer{Value: int64(len(a.Elements))}
70 | }
71 |
72 | func (a *Array) last() Object {
73 | length := len(a.Elements)
74 | if length > 0 {
75 | return a.Elements[length-1]
76 | }
77 | return &Null{}
78 | }
79 |
80 | func (a *Array) push(args []Object) Object {
81 | a.Elements = append(a.Elements, args...)
82 | return a
83 | }
84 |
85 | func (a *Array) join(args []Object) Object {
86 | if len(args) > 1 {
87 | return newError("Samahani, tunahitaji Hoja 1 au 0, wewe umeweka %d", len(args))
88 | }
89 | if len(a.Elements) > 0 {
90 | glue := ""
91 | if len(args) == 1 {
92 | glue = args[0].(*String).Value
93 | }
94 | length := len(a.Elements)
95 | newElements := make([]string, length)
96 | for k, v := range a.Elements {
97 | newElements[k] = v.Inspect()
98 | }
99 | return &String{Value: strings.Join(newElements, glue)}
100 | } else {
101 | return &String{Value: ""}
102 | }
103 | }
104 |
105 | func (a *Array) filter(args []Object) Object {
106 | if len(args) != 1 {
107 | return newError("Samahani, idadi ya hoja sii sahihi")
108 | }
109 |
110 | dummy := []Object{}
111 | filteredArr := Array{Elements: dummy}
112 | for _, obj := range a.Elements {
113 | if obj.Inspect() == args[0].Inspect() && obj.Type() == args[0].Type() {
114 | filteredArr.Elements = append(filteredArr.Elements, obj)
115 | }
116 | }
117 | return &filteredArr
118 | }
119 |
120 | func (a *Array) find(args []Object) Object {
121 | if len(args) != 1 {
122 | return newError("Samahani, idadi ya hoja sii sahihi")
123 | }
124 |
125 | for _, obj := range a.Elements {
126 | if obj.Inspect() == args[0].Inspect() && obj.Type() == args[0].Type() {
127 | return obj
128 | }
129 | }
130 | return &Null{}
131 | }
132 |
--------------------------------------------------------------------------------
/object/at.go:
--------------------------------------------------------------------------------
1 | package object
2 |
3 | import "fmt"
4 |
5 | type At struct {
6 | Instance *Instance
7 | }
8 |
9 | func (a *At) Type() ObjectType { return AT }
10 | func (a *At) Inspect() string {
11 | return fmt.Sprintf("@.%s", a.Instance.Package.Name.Value)
12 | }
13 |
--------------------------------------------------------------------------------
/object/bool.go:
--------------------------------------------------------------------------------
1 | package object
2 |
3 | type Boolean struct {
4 | Value bool
5 | }
6 |
7 | func (b *Boolean) Inspect() string {
8 | if b.Value {
9 | return "kweli"
10 | } else {
11 | return "sikweli"
12 | }
13 | }
14 | func (b *Boolean) Type() ObjectType { return BOOLEAN_OBJ }
15 |
16 | func (b *Boolean) HashKey() HashKey {
17 | var value uint64
18 |
19 | if b.Value {
20 | value = 1
21 | } else {
22 | value = 0
23 | }
24 |
25 | return HashKey{Type: b.Type(), Value: value}
26 | }
27 |
--------------------------------------------------------------------------------
/object/break.go:
--------------------------------------------------------------------------------
1 | package object
2 |
3 | type Break struct{}
4 |
5 | func (b *Break) Type() ObjectType { return BREAK_OBJ }
6 | func (b *Break) Inspect() string { return "break" }
7 |
--------------------------------------------------------------------------------
/object/builtin.go:
--------------------------------------------------------------------------------
1 | package object
2 |
3 | type BuiltinFunction func(args ...Object) Object
4 |
5 | type Builtin struct {
6 | Fn BuiltinFunction
7 | }
8 |
9 | func (b *Builtin) Inspect() string { return "builtin function" }
10 | func (b *Builtin) Type() ObjectType { return BUILTIN_OBJ }
11 |
--------------------------------------------------------------------------------
/object/byte.go:
--------------------------------------------------------------------------------
1 | package object
2 |
3 | type Byte struct {
4 | Value []byte
5 | String string
6 | }
7 |
8 | func (b *Byte) Inspect() string { return "b" + b.String }
9 | func (b *Byte) Type() ObjectType { return BYTE_OBJ }
10 |
--------------------------------------------------------------------------------
/object/continue.go:
--------------------------------------------------------------------------------
1 | package object
2 |
3 | type Continue struct{}
4 |
5 | func (c *Continue) Type() ObjectType { return CONTINUE_OBJ }
6 | func (c *Continue) Inspect() string { return "continue" }
7 |
--------------------------------------------------------------------------------
/object/dict.go:
--------------------------------------------------------------------------------
1 | package object
2 |
3 | import (
4 | "bytes"
5 | "fmt"
6 | "sort"
7 | "strings"
8 | )
9 |
10 | type DictPair struct {
11 | Key Object
12 | Value Object
13 | }
14 |
15 | type Dict struct {
16 | Pairs map[HashKey]DictPair
17 | offset int
18 | }
19 |
20 | func (d *Dict) Type() ObjectType { return DICT_OBJ }
21 | func (d *Dict) Inspect() string {
22 | var out bytes.Buffer
23 |
24 | pairs := []string{}
25 |
26 | for _, pair := range d.Pairs {
27 | pairs = append(pairs, fmt.Sprintf("%s: %s", pair.Key.Inspect(), pair.Value.Inspect()))
28 | }
29 |
30 | out.WriteString("{")
31 | out.WriteString(strings.Join(pairs, ", "))
32 | out.WriteString("}")
33 |
34 | return out.String()
35 | }
36 |
37 | func (d *Dict) Next() (Object, Object) {
38 | idx := 0
39 | dict := make(map[string]DictPair)
40 | var keys []string
41 | for _, v := range d.Pairs {
42 | dict[v.Key.Inspect()] = v
43 | keys = append(keys, v.Key.Inspect())
44 | }
45 |
46 | sort.Strings(keys)
47 |
48 | for _, k := range keys {
49 | if d.offset == idx {
50 | d.offset += 1
51 | return dict[k].Key, dict[k].Value
52 | }
53 | idx += 1
54 | }
55 | return nil, nil
56 | }
57 |
58 | func (d *Dict) Reset() {
59 | d.offset = 0
60 | }
61 |
--------------------------------------------------------------------------------
/object/environment.go:
--------------------------------------------------------------------------------
1 | package object
2 |
3 | func NewEnclosedEnvironment(outer *Environment) *Environment {
4 | env := NewEnvironment()
5 | env.outer = outer
6 | return env
7 | }
8 |
9 | func NewEnvironment() *Environment {
10 | s := make(map[string]Object)
11 | return &Environment{store: s, outer: nil}
12 | }
13 |
14 | type Environment struct {
15 | store map[string]Object
16 | outer *Environment
17 | }
18 |
19 | func (e *Environment) Get(name string) (Object, bool) {
20 | obj, ok := e.store[name]
21 |
22 | if !ok && e.outer != nil {
23 | obj, ok = e.outer.Get(name)
24 | }
25 | return obj, ok
26 | }
27 |
28 | func (e *Environment) Set(name string, val Object) Object {
29 | e.store[name] = val
30 | return val
31 | }
32 |
33 | func (e *Environment) Del(name string) bool {
34 | _, ok := e.store[name]
35 | if ok {
36 | delete(e.store, name)
37 | }
38 | return true
39 | }
40 |
--------------------------------------------------------------------------------
/object/error.go:
--------------------------------------------------------------------------------
1 | package object
2 |
3 | import "fmt"
4 |
5 | type Error struct {
6 | Message string
7 | }
8 |
9 | func (e *Error) Inspect() string {
10 | msg := fmt.Sprintf("\x1b[%dm%s\x1b[0m", 31, "Kosa: ")
11 | return msg + e.Message
12 | }
13 | func (e *Error) Type() ObjectType { return ERROR_OBJ }
14 |
--------------------------------------------------------------------------------
/object/file.go:
--------------------------------------------------------------------------------
1 | package object
2 |
3 | import (
4 | "os"
5 | )
6 |
7 | type File struct {
8 | Filename string
9 | Content string
10 | }
11 |
12 | func (f *File) Type() ObjectType { return FILE_OBJ }
13 | func (f *File) Inspect() string { return f.Filename }
14 | func (f *File) Method(method string, args []Object) Object {
15 | switch method {
16 | case "soma":
17 | return f.read(args)
18 | case "andika":
19 | return f.write(args)
20 | case "ongeza":
21 | return f.append(args)
22 | }
23 | return nil
24 | }
25 |
26 | func (f *File) read(args []Object) Object {
27 | if len(args) != 0 {
28 | return newError("Samahani, tunahitaji Hoja 0, wewe umeweka %d", len(args))
29 | }
30 | return &String{Value: f.Content}
31 | }
32 |
33 | func (f *File) write(args []Object) Object {
34 | if len(args) != 1 {
35 | return newError("Samahani, tunahitaji Hoja 1, wewe umeweka %d", len(args))
36 | }
37 | content, ok := args[0].(*String)
38 | if !ok {
39 | return newError("Samahani, hoja lazima iwe Tungo")
40 | }
41 | err := os.WriteFile(f.Filename, []byte(content.Value), 0644)
42 | if err != nil {
43 | return newError("Hitilafu katika kuandika faili: %s", err.Error())
44 | }
45 | f.Content = content.Value
46 | return &Boolean{Value: true}
47 | }
48 |
49 | func (f *File) append(args []Object) Object {
50 | if len(args) != 1 {
51 | return newError("Samahani, tunahitaji Hoja 1, wewe umeweka %d", len(args))
52 | }
53 | content, ok := args[0].(*String)
54 | if !ok {
55 | return newError("Samahani, hoja lazima iwe Tungo")
56 | }
57 | file, err := os.OpenFile(f.Filename, os.O_APPEND|os.O_WRONLY, 0644)
58 | if err != nil {
59 | return newError("Hitilafu katika kufungua faili: %s", err.Error())
60 | }
61 | defer file.Close()
62 | _, err = file.WriteString(content.Value)
63 | if err != nil {
64 | return newError("Hitilafu katika kuongeza kwa faili: %s", err.Error())
65 | }
66 | f.Content += content.Value
67 | return &Boolean{Value: true}
68 | }
69 |
--------------------------------------------------------------------------------
/object/float.go:
--------------------------------------------------------------------------------
1 | package object
2 |
3 | import (
4 | "hash/fnv"
5 | "strconv"
6 | )
7 |
8 | type Float struct {
9 | Value float64
10 | }
11 |
12 | func (f *Float) Inspect() string { return strconv.FormatFloat(f.Value, 'f', -1, 64) }
13 | func (f *Float) Type() ObjectType { return FLOAT_OBJ }
14 |
15 | func (f *Float) HashKey() HashKey {
16 | h := fnv.New64a()
17 | h.Write([]byte(f.Inspect()))
18 | return HashKey{Type: f.Type(), Value: h.Sum64()}
19 | }
20 |
--------------------------------------------------------------------------------
/object/function.go:
--------------------------------------------------------------------------------
1 | package object
2 |
3 | import (
4 | "bytes"
5 | "strings"
6 |
7 | "github.com/NuruProgramming/Nuru/ast"
8 | )
9 |
10 | type Function struct {
11 | Name string
12 | Parameters []*ast.Identifier
13 | Defaults map[string]ast.Expression
14 | Body *ast.BlockStatement
15 | Env *Environment
16 | }
17 |
18 | func (f *Function) Type() ObjectType { return FUNCTION_OBJ }
19 | func (f *Function) Inspect() string {
20 | var out bytes.Buffer
21 |
22 | params := []string{}
23 | for _, p := range f.Parameters {
24 | params = append(params, p.String())
25 | }
26 |
27 | out.WriteString("unda")
28 | out.WriteString("(")
29 | out.WriteString(strings.Join(params, ", "))
30 | out.WriteString(") {\n")
31 | out.WriteString(f.Body.String())
32 | out.WriteString("\n}")
33 |
34 | return out.String()
35 | }
36 |
--------------------------------------------------------------------------------
/object/instance.go:
--------------------------------------------------------------------------------
1 | package object
2 |
3 | import "fmt"
4 |
5 | type Instance struct {
6 | Package *Package
7 | Env *Environment
8 | }
9 |
10 | func (i *Instance) Type() ObjectType { return INSTANCE }
11 | func (i *Instance) Inspect() string {
12 | return fmt.Sprintf("Pakeji: %s", i.Package.Name.Value)
13 | }
14 |
--------------------------------------------------------------------------------
/object/integer.go:
--------------------------------------------------------------------------------
1 | package object
2 |
3 | import "fmt"
4 |
5 | type Integer struct {
6 | Value int64
7 | }
8 |
9 | func (i *Integer) Inspect() string { return fmt.Sprintf("%d", i.Value) }
10 | func (i *Integer) Type() ObjectType { return INTEGER_OBJ }
11 |
12 | func (i *Integer) HashKey() HashKey {
13 | return HashKey{Type: i.Type(), Value: uint64(i.Value)}
14 | }
15 |
--------------------------------------------------------------------------------
/object/module.go:
--------------------------------------------------------------------------------
1 | package object
2 |
3 | type ModuleFunction func(args []Object, defs map[string]Object) Object
4 |
5 | type Module struct {
6 | Name string
7 | Functions map[string]ModuleFunction
8 | }
9 |
10 | func (m *Module) Type() ObjectType {
11 | switch m.Name {
12 | case "time":
13 | return TIME_OBJ
14 | case "json":
15 | return JSON_OBJ
16 | default:
17 | return MODULE_OBJ
18 | }
19 | }
20 | func (m *Module) Inspect() string { return "Module: " + m.Name }
21 |
--------------------------------------------------------------------------------
/object/null.go:
--------------------------------------------------------------------------------
1 | package object
2 |
3 | type Null struct{}
4 |
5 | func (n *Null) Inspect() string { return "null" }
6 | func (n *Null) Type() ObjectType { return NULL_OBJ }
7 |
--------------------------------------------------------------------------------
/object/object.go:
--------------------------------------------------------------------------------
1 | package object
2 |
3 | import (
4 | "fmt"
5 | )
6 |
7 | type ObjectType string
8 |
9 | const (
10 | INTEGER_OBJ = "NAMBA"
11 | FLOAT_OBJ = "DESIMALI"
12 | BOOLEAN_OBJ = "BOOLEAN"
13 | NULL_OBJ = "TUPU"
14 | RETURN_VALUE_OBJ = "RUDISHA"
15 | ERROR_OBJ = "KOSA"
16 | FUNCTION_OBJ = "UNDO (FUNCTION)"
17 | STRING_OBJ = "NENO"
18 | BUILTIN_OBJ = "YA_NDANI"
19 | ARRAY_OBJ = "ORODHA"
20 | DICT_OBJ = "KAMUSI"
21 | CONTINUE_OBJ = "ENDELEA"
22 | BREAK_OBJ = "VUNJA"
23 | FILE_OBJ = "FAILI"
24 | TIME_OBJ = "MUDA"
25 | JSON_OBJ = "JSONI"
26 | MODULE_OBJ = "MODULE"
27 | BYTE_OBJ = "BYTE"
28 | PACKAGE_OBJ = "PAKEJI"
29 | INSTANCE = "PAKEJI"
30 | AT = "@"
31 | )
32 |
33 | type Object interface {
34 | Type() ObjectType
35 | Inspect() string
36 | }
37 |
38 | type HashKey struct {
39 | Type ObjectType
40 | Value uint64
41 | }
42 |
43 | type Hashable interface {
44 | HashKey() HashKey
45 | }
46 |
47 | // Iterable interface for dicts, strings and arrays
48 | type Iterable interface {
49 | Next() (Object, Object)
50 | Reset()
51 | }
52 |
53 | func newError(format string, a ...interface{}) *Error {
54 | format = fmt.Sprintf("\x1b[%dm%s\x1b[0m", 31, format)
55 | return &Error{Message: fmt.Sprintf(format, a...)}
56 | }
57 |
--------------------------------------------------------------------------------
/object/object_test.go:
--------------------------------------------------------------------------------
1 | package object
2 |
3 | import "testing"
4 |
5 | func TestStringHashKey(t *testing.T) {
6 | hello1 := &String{Value: "Hello World"}
7 | hello2 := &String{Value: "Hello World"}
8 | diff1 := &String{Value: "My name is Avi"}
9 | diff2 := &String{Value: "My name is Avi"}
10 |
11 | if hello1.HashKey() != hello2.HashKey() {
12 | t.Errorf("string with the same content have different dict keys")
13 | }
14 |
15 | if diff1.HashKey() != diff2.HashKey() {
16 | t.Errorf("String with the same content have different dict keys")
17 | }
18 |
19 | if hello1.HashKey() == diff1.HashKey() {
20 | t.Errorf("Strings with different content have the same dict keys")
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/object/package.go:
--------------------------------------------------------------------------------
1 | package object
2 |
3 | import (
4 | "fmt"
5 |
6 | "github.com/NuruProgramming/Nuru/ast"
7 | )
8 |
9 | type Package struct {
10 | Name *ast.Identifier
11 | Env *Environment
12 | Scope *Environment
13 | }
14 |
15 | func (p *Package) Type() ObjectType { return PACKAGE_OBJ }
16 | func (p *Package) Inspect() string {
17 | return fmt.Sprintf("Pakeji: %s", p.Name.Value)
18 | }
19 |
--------------------------------------------------------------------------------
/object/return.go:
--------------------------------------------------------------------------------
1 | package object
2 |
3 | type ReturnValue struct {
4 | Value Object
5 | }
6 |
7 | func (rv *ReturnValue) Inspect() string { return rv.Value.Inspect() }
8 | func (rv *ReturnValue) Type() ObjectType { return RETURN_VALUE_OBJ }
9 |
--------------------------------------------------------------------------------
/object/strings.go:
--------------------------------------------------------------------------------
1 | package object
2 |
3 | import (
4 | "fmt"
5 | "hash/fnv"
6 | "strconv"
7 | "strings"
8 | )
9 |
10 | type String struct {
11 | Value string
12 | offset int
13 | }
14 |
15 | func (s *String) Inspect() string { return s.Value }
16 | func (s *String) Type() ObjectType { return STRING_OBJ }
17 | func (s *String) HashKey() HashKey {
18 | h := fnv.New64a()
19 | h.Write([]byte(s.Value))
20 |
21 | return HashKey{Type: s.Type(), Value: h.Sum64()}
22 | }
23 | func (s *String) Next() (Object, Object) {
24 | offset := s.offset
25 | if len(s.Value) > offset {
26 | s.offset = offset + 1
27 | return &Integer{Value: int64(offset)}, &String{Value: string(s.Value[offset])}
28 | }
29 | return nil, nil
30 | }
31 | func (s *String) Reset() {
32 | s.offset = 0
33 | }
34 | func (s *String) Method(method string, args []Object) Object {
35 | switch method {
36 | case "idadi":
37 | return s.len(args)
38 | case "herufikubwa":
39 | return s.upper(args)
40 | case "herufindogo":
41 | return s.lower(args)
42 | case "gawa":
43 | return s.split(args)
44 | case "panga":
45 | return s.format(args)
46 | default:
47 | return newError("Samahani, kiendesha hiki hakitumiki na tungo (Neno)")
48 | }
49 | }
50 |
51 | func (s *String) len(args []Object) Object {
52 | if len(args) != 0 {
53 | return newError("Samahani, tunahitaji Hoja 0, wewe umeweka %d", len(args))
54 | }
55 | return &Integer{Value: int64(len(s.Value))}
56 | }
57 |
58 | func (s *String) upper(args []Object) Object {
59 | if len(args) != 0 {
60 | return newError("Samahani, tunahitaji Hoja 0, wewe umeweka %d", len(args))
61 | }
62 | return &String{Value: strings.ToUpper(s.Value)}
63 | }
64 |
65 | func (s *String) lower(args []Object) Object {
66 | if len(args) != 0 {
67 | return newError("Samahani, tunahitaji Hoja 0, wewe umeweka %d", len(args))
68 | }
69 | return &String{Value: strings.ToLower(s.Value)}
70 | }
71 |
72 | func (s *String) split(args []Object) Object {
73 | if len(args) > 1 {
74 | return newError("Samahani, tunahitaji Hoja 1 au 0, wewe umeweka %d", len(args))
75 | }
76 | sep := " "
77 | if len(args) == 1 {
78 | sep = args[0].(*String).Value
79 | }
80 | parts := strings.Split(s.Value, sep)
81 | length := len(parts)
82 | elements := make([]Object, length)
83 | for k, v := range parts {
84 | elements[k] = &String{Value: v}
85 | }
86 | return &Array{Elements: elements}
87 | }
88 |
89 | func (s *String) format(args []Object) Object {
90 | value, err := formatStr(s.Value, args)
91 |
92 | if err != nil {
93 | return newError(err.Error())
94 | }
95 |
96 | return &String{Value: value}
97 | }
98 |
99 | func formatStr(format string, options []Object) (string, error) {
100 | var str strings.Builder
101 | var val strings.Builder
102 | var check_val bool
103 | var opts_len int = len(options)
104 |
105 | var escapeChar bool
106 |
107 | type optM struct {
108 | val bool
109 | obj Object
110 | }
111 |
112 | var optionsMap = make(map[int]optM, opts_len)
113 |
114 | for i, optm := range options {
115 | optionsMap[i] = optM{val: false, obj: optm}
116 | }
117 |
118 | for _, opt := range format {
119 |
120 | if !escapeChar && opt == '\\' {
121 | escapeChar = true
122 | continue
123 | }
124 |
125 | if opt == '{' && !escapeChar {
126 | check_val = true
127 | continue
128 | }
129 |
130 | if escapeChar {
131 | if opt != '{' && opt != '}' {
132 | str.WriteRune('\\')
133 | }
134 | escapeChar = false
135 | }
136 |
137 | if check_val && opt == '}' {
138 | vstr := strings.TrimSpace(val.String())
139 | arrv, err := strconv.Atoi(vstr)
140 | if err != nil {
141 | return "", fmt.Errorf(fmt.Sprintf("Ulichopeana si NAMBA, jaribu tena: `%s'", vstr))
142 | }
143 |
144 | oVal, exists := optionsMap[arrv]
145 |
146 | if !exists {
147 | return "", fmt.Errorf(fmt.Sprintf("Nambari ya chaguo unalolitaka %d ni kubwa kuliko ulizopeana (%d)", arrv, opts_len))
148 | }
149 |
150 | str.WriteString(oVal.obj.Inspect())
151 | optionsMap[arrv] = optM{val: true, obj: oVal.obj}
152 |
153 | check_val = false
154 | val.Reset()
155 | continue
156 | }
157 |
158 | if check_val {
159 | val.WriteRune(opt)
160 | continue
161 | }
162 |
163 | str.WriteRune(opt)
164 | }
165 |
166 | if check_val {
167 | return "", fmt.Errorf(fmt.Sprintf("Haukufunga '{', tuliokota kabla ya kufika mwisho `%s'", val.String()))
168 | }
169 |
170 | for _, v := range optionsMap {
171 | if !v.val {
172 | return "", fmt.Errorf(fmt.Sprintf("Ulipeana hili chaguo (%s) {%s} lakini haukutumia", v.obj.Inspect(), v.obj.Type()))
173 | }
174 | }
175 |
176 | return str.String(), nil
177 | }
178 |
--------------------------------------------------------------------------------
/object/time.go:
--------------------------------------------------------------------------------
1 | package object
2 |
3 | import (
4 | "fmt"
5 | "strconv"
6 | "time"
7 | )
8 |
9 | type Time struct {
10 | TimeValue string
11 | }
12 |
13 | func (t *Time) Type() ObjectType { return TIME_OBJ }
14 | func (t *Time) Inspect() string { return t.TimeValue }
15 | func (t *Time) Method(method string, args []Object, defs map[string]Object) Object {
16 | switch method {
17 | case "ongeza":
18 | return t.add(args, defs)
19 | case "tangu":
20 | return t.since(args, defs)
21 | }
22 | return nil
23 | }
24 |
25 | func (t *Time) add(args []Object, defs map[string]Object) Object {
26 | if len(defs) != 0 {
27 | var sec, min, hr, d, m, y int
28 | for k, v := range defs {
29 | objvalue := v.Inspect()
30 | inttime, err := strconv.Atoi(objvalue)
31 | if err != nil {
32 | return newError("namba tu zinaruhusiwa kwenye hoja")
33 | }
34 | switch k {
35 | case "sekunde":
36 | sec = inttime
37 | case "dakika":
38 | min = inttime
39 | case "saa":
40 | hr = inttime
41 | case "siku":
42 | d = inttime
43 | case "miezi":
44 | m = inttime
45 | case "miaka":
46 | y = inttime
47 | default:
48 | return newError("Hukuweka muda sahihi")
49 | }
50 | }
51 | cur_time, _ := time.Parse("15:04:05 02-01-2006", t.Inspect())
52 | next_time := cur_time.
53 | Add(time.Duration(sec)*time.Second).
54 | Add(time.Duration(min)*time.Minute).
55 | Add(time.Duration(hr)*time.Hour).
56 | AddDate(y, m, d)
57 | return &Time{TimeValue: string(next_time.Format("15:04:05 02-01-2006"))}
58 | }
59 |
60 | if len(args) != 1 {
61 | return newError("Samahani, tunahitaji Hoja 1, wewe umeweka %d", len(args))
62 | }
63 |
64 | cur_time, _ := time.Parse("15:04:05 02-01-2006", t.Inspect())
65 |
66 | objvalue := args[0].Inspect()
67 | inttime, err := strconv.Atoi(objvalue)
68 |
69 | if err != nil {
70 | return newError("namba tu zinaruhusiwa kwenye hoja")
71 | }
72 |
73 | next_time := cur_time.Add(time.Duration(inttime) * time.Hour)
74 | return &Time{TimeValue: string(next_time.Format("15:04:05 02-01-2006"))}
75 | }
76 |
77 | func (t *Time) since(args []Object, defs map[string]Object) Object {
78 | if len(defs) != 0 {
79 | return &Error{Message: "Hoja hii hairuhusiwi"}
80 | }
81 | if len(args) != 1 {
82 | return &Error{Message: "tunahitaji hoja moja tu"}
83 | }
84 |
85 | var (
86 | o time.Time
87 | err error
88 | )
89 |
90 | switch m := args[0].(type) {
91 | case *Time:
92 | o, _ = time.Parse("15:04:05 02-01-2006", m.TimeValue)
93 | case *String:
94 | o, err = time.Parse("15:04:05 02-01-2006", m.Value)
95 | if err != nil {
96 | return &Error{Message: fmt.Sprintf("Hoja %s sii sahihi", args[0].Inspect())}
97 | }
98 | default:
99 | return &Error{Message: fmt.Sprintf("Hoja %s sii sahihi", args[0].Inspect())}
100 | }
101 |
102 | ct, _ := time.Parse("15:04:05 02-01-2006", t.TimeValue)
103 |
104 | diff := ct.Sub(o)
105 | durationInSeconds := diff.Seconds()
106 |
107 | return &Integer{Value: int64(durationInSeconds)}
108 | }
109 |
--------------------------------------------------------------------------------
/parser/arrays.go:
--------------------------------------------------------------------------------
1 | package parser
2 |
3 | import (
4 | "github.com/NuruProgramming/Nuru/ast"
5 | "github.com/NuruProgramming/Nuru/token"
6 | )
7 |
8 | func (p *Parser) parseArrayLiteral() ast.Expression {
9 | array := &ast.ArrayLiteral{Token: p.curToken}
10 |
11 | array.Elements = p.parseExpressionList(token.RBRACKET)
12 |
13 | return array
14 | }
15 |
16 | func (p *Parser) parseExpressionList(end token.TokenType) []ast.Expression {
17 | list := []ast.Expression{}
18 |
19 | if p.peekTokenIs(end) {
20 | p.nextToken()
21 | return list
22 | }
23 |
24 | p.nextToken()
25 | list = append(list, p.parseExpression(LOWEST))
26 |
27 | for p.peekTokenIs(token.COMMA) {
28 | p.nextToken()
29 | p.nextToken()
30 | list = append(list, p.parseExpression(LOWEST))
31 | }
32 |
33 | if !p.expectPeek(end) {
34 | return nil
35 | }
36 | return list
37 | }
38 |
--------------------------------------------------------------------------------
/parser/assignEqual.go:
--------------------------------------------------------------------------------
1 | package parser
2 |
3 | import (
4 | "fmt"
5 |
6 | "github.com/NuruProgramming/Nuru/ast"
7 | )
8 |
9 | func (p *Parser) parseAssignEqualExpression(exp ast.Expression) ast.Expression {
10 | switch node := exp.(type) {
11 | case *ast.Identifier:
12 | e := &ast.AssignEqual{
13 | Token: p.curToken,
14 | Left: exp.(*ast.Identifier),
15 | }
16 | precendence := p.curPrecedence()
17 | p.nextToken()
18 | e.Value = p.parseExpression(precendence)
19 | return e
20 | case *ast.IndexExpression:
21 | ae := &ast.AssignmentExpression{Token: p.curToken, Left: exp}
22 |
23 | p.nextToken()
24 |
25 | ae.Value = p.parseExpression(LOWEST)
26 |
27 | return ae
28 | default:
29 | if node != nil {
30 | msg := fmt.Sprintf("Mstari %d:Tulitegemea kupata kitambulishi au array, badala yake tumepata: %s", p.curToken.Line, node.TokenLiteral())
31 | p.errors = append(p.errors, msg)
32 | } else {
33 | msg := fmt.Sprintf("Mstari %d: Umekosea mkuu", p.curToken.Line)
34 | p.errors = append(p.errors, msg)
35 | }
36 | return nil
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/parser/assignment.go:
--------------------------------------------------------------------------------
1 | package parser
2 |
3 | import (
4 | "fmt"
5 |
6 | "github.com/NuruProgramming/Nuru/ast"
7 | )
8 |
9 | func (p *Parser) parseAssignmentExpression(exp ast.Expression) ast.Expression {
10 | switch node := exp.(type) {
11 | case *ast.Identifier:
12 | e := &ast.Assign{
13 | Token: p.curToken,
14 | Name: exp.(*ast.Identifier),
15 | }
16 | precedence := p.curPrecedence()
17 | p.nextToken()
18 | e.Value = p.parseExpression(precedence)
19 | return e
20 |
21 | case *ast.IndexExpression:
22 | case *ast.PropertyExpression:
23 | e := &ast.PropertyAssignment{
24 | Token: p.curToken,
25 | Name: exp.(*ast.PropertyExpression),
26 | }
27 | precedence := p.curPrecedence()
28 | p.nextToken()
29 | e.Value = p.parseExpression(precedence)
30 | return e
31 | default:
32 | if node != nil {
33 | msg := fmt.Sprintf("Mstari %d:Tulitegemea kupata kitambulishi au array, badala yake tumepata: %s", p.curToken.Line, node.TokenLiteral())
34 | p.errors = append(p.errors, msg)
35 | } else {
36 | msg := fmt.Sprintf("Mstari %d: Umekosea mkuu", p.curToken.Line)
37 | p.errors = append(p.errors, msg)
38 | }
39 | return nil
40 | }
41 |
42 | ae := &ast.AssignmentExpression{Token: p.curToken, Left: exp}
43 |
44 | p.nextToken()
45 |
46 | ae.Value = p.parseExpression(LOWEST)
47 |
48 | return ae
49 | }
50 |
--------------------------------------------------------------------------------
/parser/at.go:
--------------------------------------------------------------------------------
1 | package parser
2 |
3 | import "github.com/NuruProgramming/Nuru/ast"
4 |
5 | func (p *Parser) parseAt() ast.Expression {
6 | return &ast.At{Token: p.curToken}
7 | }
8 |
--------------------------------------------------------------------------------
/parser/boolean.go:
--------------------------------------------------------------------------------
1 | package parser
2 |
3 | import (
4 | "github.com/NuruProgramming/Nuru/ast"
5 | "github.com/NuruProgramming/Nuru/token"
6 | )
7 |
8 | func (p *Parser) parseBoolean() ast.Expression {
9 | return &ast.Boolean{Token: p.curToken, Value: p.curTokenIs(token.TRUE)}
10 | }
11 |
--------------------------------------------------------------------------------
/parser/break.go:
--------------------------------------------------------------------------------
1 | package parser
2 |
3 | import (
4 | "github.com/NuruProgramming/Nuru/ast"
5 | "github.com/NuruProgramming/Nuru/token"
6 | )
7 |
8 | func (p *Parser) parseBreak() *ast.Break {
9 | stmt := &ast.Break{Token: p.curToken}
10 | for p.curTokenIs(token.SEMICOLON) {
11 | p.nextToken()
12 | }
13 | return stmt
14 | }
15 |
--------------------------------------------------------------------------------
/parser/continue.go:
--------------------------------------------------------------------------------
1 | package parser
2 |
3 | import (
4 | "github.com/NuruProgramming/Nuru/ast"
5 | "github.com/NuruProgramming/Nuru/token"
6 | )
7 |
8 | func (p *Parser) parseContinue() *ast.Continue {
9 | stmt := &ast.Continue{Token: p.curToken}
10 | for p.curTokenIs(token.SEMICOLON) {
11 | p.nextToken()
12 | }
13 | return stmt
14 | }
15 |
--------------------------------------------------------------------------------
/parser/dict.go:
--------------------------------------------------------------------------------
1 | package parser
2 |
3 | import (
4 | "github.com/NuruProgramming/Nuru/ast"
5 | "github.com/NuruProgramming/Nuru/token"
6 | )
7 |
8 | func (p *Parser) parseDictLiteral() ast.Expression {
9 | dict := &ast.DictLiteral{Token: p.curToken}
10 | dict.Pairs = make(map[ast.Expression]ast.Expression)
11 |
12 | for !p.peekTokenIs(token.RBRACE) {
13 | p.nextToken()
14 | key := p.parseExpression(LOWEST)
15 |
16 | if !p.expectPeek(token.COLON) {
17 | return nil
18 | }
19 |
20 | p.nextToken()
21 | value := p.parseExpression(LOWEST)
22 |
23 | dict.Pairs[key] = value
24 |
25 | if !p.peekTokenIs(token.RBRACE) && !p.expectPeek(token.COMMA) {
26 | return nil
27 | }
28 | }
29 |
30 | if !p.expectPeek(token.RBRACE) {
31 | return nil
32 | }
33 |
34 | return dict
35 | }
36 |
--------------------------------------------------------------------------------
/parser/dot.go:
--------------------------------------------------------------------------------
1 | package parser
2 |
3 | import (
4 | "github.com/NuruProgramming/Nuru/ast"
5 | "github.com/NuruProgramming/Nuru/token"
6 | )
7 |
8 | func (p *Parser) parseMethod(obj ast.Expression) ast.Expression {
9 | tok := p.curToken
10 | precedence := p.curPrecedence()
11 | p.nextToken()
12 | if p.peekTokenIs(token.LPAREN) {
13 | exp := &ast.MethodExpression{Token: tok, Object: obj}
14 | exp.Method = p.parseExpression(precedence)
15 | if !p.expectPeek(token.LPAREN) {
16 | return nil
17 | }
18 |
19 | exp.Defaults = make(map[string]ast.Expression)
20 |
21 | for !p.peekTokenIs(token.RPAREN) {
22 | p.nextToken()
23 | if p.curTokenIs(token.COMMA) {
24 | continue
25 | }
26 | if p.peekTokenIs(token.ASSIGN) {
27 | name := p.curToken.Literal
28 | p.nextToken()
29 | p.nextToken()
30 | val := p.parseExpression(LOWEST)
31 | exp.Defaults[name] = val
32 | } else {
33 | exp.Arguments = append(exp.Arguments, p.parseExpression(LOWEST))
34 | }
35 | }
36 |
37 | if !p.expectPeek(token.RPAREN) {
38 | return nil
39 | }
40 |
41 | return exp
42 | } else {
43 | exp := &ast.PropertyExpression{Token: tok, Object: obj}
44 | exp.Property = p.parseIdentifier()
45 | return exp
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/parser/float.go:
--------------------------------------------------------------------------------
1 | package parser
2 |
3 | import (
4 | "fmt"
5 | "strconv"
6 |
7 | "github.com/NuruProgramming/Nuru/ast"
8 | )
9 |
10 | func (p *Parser) parseFloatLiteral() ast.Expression {
11 | fl := &ast.FloatLiteral{Token: p.curToken}
12 | value, err := strconv.ParseFloat(p.curToken.Literal, 64)
13 | if err != nil {
14 | msg := fmt.Sprintf("Mstari %d: Hatuwezi kuparse %q kama desimali", p.curToken.Line, p.curToken.Literal)
15 | p.errors = append(p.errors, msg)
16 | return nil
17 | }
18 | fl.Value = value
19 | return fl
20 | }
21 |
--------------------------------------------------------------------------------
/parser/for.go:
--------------------------------------------------------------------------------
1 | package parser
2 |
3 | import (
4 | "github.com/NuruProgramming/Nuru/ast"
5 | "github.com/NuruProgramming/Nuru/token"
6 | )
7 |
8 | func (p *Parser) parseForExpression() ast.Expression {
9 | expression := &ast.For{Token: p.curToken}
10 | p.nextToken()
11 | if !p.curTokenIs(token.IDENT) {
12 | return nil
13 | }
14 | if !p.peekTokenIs(token.ASSIGN) {
15 | return p.parseForInExpression(expression)
16 | }
17 |
18 | // In future will allow: kwa i = 0; i<10; i++ {andika(i)}
19 | // expression.Identifier = p.curToken.Literal
20 | // expression.StarterName = &ast.Identifier{Token: p.curToken, Value: p.curToken.Literal}
21 | // if expression.StarterName == nil {
22 | // return nil
23 | // }
24 | // if !p.expectPeek(token.ASSIGN) {
25 | // return nil
26 | // }
27 |
28 | // p.nextToken()
29 |
30 | // expression.StarterValue = p.parseExpression(LOWEST)
31 | // // expression.Starter = p.parseExpression(LOWEST)
32 | // if expression.StarterValue == nil {
33 | // return nil
34 | // }
35 | // p.nextToken()
36 | // for p.curTokenIs(token.SEMICOLON) {
37 | // p.nextToken()
38 | // }
39 | // expression.Condition = p.parseExpression(LOWEST)
40 | // if expression.Condition == nil {
41 | // return nil
42 | // }
43 | // p.nextToken()
44 | // for p.curTokenIs(token.SEMICOLON) {
45 | // p.nextToken()
46 | // }
47 | // expression.Closer = p.parseExpression(LOWEST)
48 | // if expression.Closer == nil {
49 | // return nil
50 | // }
51 | // p.nextToken()
52 | // for p.curTokenIs(token.SEMICOLON) {
53 | // p.nextToken()
54 | // }
55 | // if !p.curTokenIs(token.LBRACE) {
56 | // return nil
57 | // }
58 | // expression.Block = p.parseBlockStatement()
59 | // return expression
60 | return nil
61 | }
62 |
63 | func (p *Parser) parseForInExpression(initialExpression *ast.For) ast.Expression {
64 | expression := &ast.ForIn{Token: initialExpression.Token}
65 | if !p.curTokenIs(token.IDENT) {
66 | return nil
67 | }
68 | val := p.curToken.Literal
69 | var key string
70 | p.nextToken()
71 | if p.curTokenIs(token.COMMA) {
72 | p.nextToken()
73 | if !p.curTokenIs(token.IDENT) {
74 | return nil
75 | }
76 | key = val
77 | val = p.curToken.Literal
78 | p.nextToken()
79 | }
80 | expression.Key = key
81 | expression.Value = val
82 | if !p.curTokenIs(token.IN) {
83 | return nil
84 | }
85 | p.nextToken()
86 | expression.Iterable = p.parseExpression(LOWEST)
87 | if !p.expectPeek(token.LBRACE) {
88 | return nil
89 | }
90 | expression.Block = p.parseBlockStatement()
91 | return expression
92 | }
93 |
--------------------------------------------------------------------------------
/parser/function.go:
--------------------------------------------------------------------------------
1 | package parser
2 |
3 | import (
4 | "github.com/NuruProgramming/Nuru/ast"
5 | "github.com/NuruProgramming/Nuru/token"
6 | )
7 |
8 | func (p *Parser) parseFunctionLiteral() ast.Expression {
9 | lit := &ast.FunctionLiteral{Token: p.curToken}
10 |
11 | if p.peekTokenIs(token.IDENT) {
12 | p.nextToken()
13 | lit.Name = p.curToken.Literal
14 | }
15 |
16 | if !p.expectPeek(token.LPAREN) {
17 | return nil
18 | }
19 |
20 | if !p.parseFunctionParameters(lit) {
21 | return nil
22 | }
23 |
24 | if !p.expectPeek(token.LBRACE) {
25 | return nil
26 | }
27 |
28 | lit.Body = p.parseBlockStatement()
29 |
30 | return lit
31 | }
32 |
33 | func (p *Parser) parseFunctionParameters(lit *ast.FunctionLiteral) bool {
34 | lit.Defaults = make(map[string]ast.Expression)
35 | for !p.peekTokenIs(token.RPAREN) {
36 | p.nextToken()
37 |
38 | if p.curTokenIs(token.COMMA) {
39 | continue
40 | }
41 |
42 | ident := &ast.Identifier{Token: p.curToken, Value: p.curToken.Literal}
43 | lit.Parameters = append(lit.Parameters, ident)
44 |
45 | if p.peekTokenIs(token.ASSIGN) {
46 | p.nextToken()
47 | p.nextToken()
48 | lit.Defaults[ident.Value] = p.parseExpression(LOWEST)
49 | } else {
50 | if len(lit.Defaults) > 0 {
51 | return false
52 | }
53 | }
54 |
55 | if !(p.peekTokenIs(token.COMMA) || p.peekTokenIs(token.RPAREN)) {
56 | return false
57 | }
58 | }
59 |
60 | return p.expectPeek(token.RPAREN)
61 | }
62 |
63 | func (p *Parser) parseCallExpression(function ast.Expression) ast.Expression {
64 | exp := &ast.CallExpression{Token: p.curToken, Function: function}
65 | exp.Arguments = p.parseExpressionList(token.RPAREN)
66 | return exp
67 | }
68 |
--------------------------------------------------------------------------------
/parser/identifier.go:
--------------------------------------------------------------------------------
1 | package parser
2 |
3 | import (
4 | "github.com/NuruProgramming/Nuru/ast"
5 | )
6 |
7 | func (p *Parser) parseIdentifier() ast.Expression {
8 | return &ast.Identifier{Token: p.curToken, Value: p.curToken.Literal}
9 | }
10 |
--------------------------------------------------------------------------------
/parser/if.go:
--------------------------------------------------------------------------------
1 | package parser
2 |
3 | import (
4 | "github.com/NuruProgramming/Nuru/ast"
5 | "github.com/NuruProgramming/Nuru/token"
6 | )
7 |
8 | func (p *Parser) parseIfExpression() ast.Expression {
9 | expression := &ast.IfExpression{Token: p.curToken}
10 |
11 | if !p.expectPeek(token.LPAREN) {
12 | return nil
13 | }
14 |
15 | p.nextToken()
16 | expression.Condition = p.parseExpression(LOWEST)
17 |
18 | if !p.expectPeek(token.RPAREN) {
19 | return nil
20 | }
21 |
22 | if !p.expectPeek(token.LBRACE) {
23 | return nil
24 | }
25 |
26 | expression.Consequence = p.parseBlockStatement()
27 |
28 | if p.peekTokenIs(token.ELSE) {
29 | p.nextToken()
30 | if p.peekTokenIs(token.IF) {
31 | p.nextToken()
32 | expression.Alternative = &ast.BlockStatement{
33 | Statements: []ast.Statement{
34 | &ast.ExpressionStatement{
35 | Expression: p.parseIfExpression(),
36 | },
37 | },
38 | }
39 | return expression
40 | }
41 |
42 | if !p.expectPeek(token.LBRACE) {
43 | return nil
44 | }
45 |
46 | expression.Alternative = p.parseBlockStatement()
47 | }
48 |
49 | return expression
50 | }
51 |
--------------------------------------------------------------------------------
/parser/import.go:
--------------------------------------------------------------------------------
1 | package parser
2 |
3 | import (
4 | "github.com/NuruProgramming/Nuru/ast"
5 | "github.com/NuruProgramming/Nuru/token"
6 | )
7 |
8 | func (p *Parser) parseImport() ast.Expression {
9 | exp := &ast.Import{Token: p.curToken}
10 | exp.Identifiers = make(map[string]*ast.Identifier)
11 | for p.curToken.Line == p.peekToken.Line {
12 | p.nextToken()
13 | identifier := &ast.Identifier{Value: p.curToken.Literal}
14 | exp.Identifiers[p.curToken.Literal] = identifier
15 | if p.peekTokenIs(token.COMMA) {
16 | p.nextToken()
17 | }
18 | if p.peekTokenIs(token.EOF) {
19 | break
20 | }
21 | }
22 |
23 | return exp
24 | }
25 |
--------------------------------------------------------------------------------
/parser/index.go:
--------------------------------------------------------------------------------
1 | package parser
2 |
3 | import (
4 | "github.com/NuruProgramming/Nuru/ast"
5 | "github.com/NuruProgramming/Nuru/token"
6 | )
7 |
8 | func (p *Parser) parseIndexExpression(left ast.Expression) ast.Expression {
9 | exp := &ast.IndexExpression{Token: p.curToken, Left: left}
10 |
11 | p.nextToken()
12 | exp.Index = p.parseExpression(LOWEST)
13 | if !p.expectPeek(token.RBRACKET) {
14 | return nil
15 | }
16 |
17 | return exp
18 | }
19 |
--------------------------------------------------------------------------------
/parser/integer.go:
--------------------------------------------------------------------------------
1 | package parser
2 |
3 | import (
4 | "fmt"
5 | "strconv"
6 |
7 | "github.com/NuruProgramming/Nuru/ast"
8 | )
9 |
10 | func (p *Parser) parseIntegerLiteral() ast.Expression {
11 | lit := &ast.IntegerLiteral{Token: p.curToken}
12 |
13 | value, err := strconv.ParseInt(p.curToken.Literal, 0, 64)
14 | if err != nil {
15 | msg := fmt.Sprintf("Mstari %d: Hatuwezi kuparse %q kama namba", p.curToken.Line, p.curToken.Literal)
16 | p.errors = append(p.errors, msg)
17 | return nil
18 | }
19 | lit.Value = value
20 |
21 | return lit
22 | }
23 |
--------------------------------------------------------------------------------
/parser/null.go:
--------------------------------------------------------------------------------
1 | package parser
2 |
3 | import (
4 | "github.com/NuruProgramming/Nuru/ast"
5 | )
6 |
7 | func (p *Parser) parseNull() ast.Expression {
8 | return &ast.Null{Token: p.curToken}
9 | }
10 |
--------------------------------------------------------------------------------
/parser/package.go:
--------------------------------------------------------------------------------
1 | package parser
2 |
3 | import (
4 | "github.com/NuruProgramming/Nuru/ast"
5 | "github.com/NuruProgramming/Nuru/token"
6 | )
7 |
8 | func (p *Parser) parsePackage() ast.Expression {
9 | expression := &ast.Package{Token: p.curToken}
10 | p.nextToken()
11 | expression.Name = &ast.Identifier{Token: p.curToken, Value: p.curToken.Literal}
12 |
13 | if !p.expectPeek(token.LBRACE) {
14 | return nil
15 | }
16 | expression.Block = p.parseBlockStatement()
17 | return expression
18 | }
19 |
--------------------------------------------------------------------------------
/parser/statements.go:
--------------------------------------------------------------------------------
1 | package parser
2 |
3 | import (
4 | "fmt"
5 |
6 | "github.com/NuruProgramming/Nuru/ast"
7 | "github.com/NuruProgramming/Nuru/token"
8 | )
9 |
10 | func (p *Parser) parseStatement() ast.Statement {
11 | switch p.curToken.Type {
12 | case token.LET:
13 | return p.parseLetStatement()
14 | case token.RETURN:
15 | return p.parseReturnStatement()
16 | case token.BREAK:
17 | return p.parseBreak()
18 | case token.CONTINUE:
19 | return p.parseContinue()
20 | default:
21 | return p.parseExpressionStatement()
22 | }
23 | }
24 |
25 | func (p *Parser) parseLetStatement() *ast.LetStatement {
26 | stmt := &ast.LetStatement{Token: p.curToken}
27 |
28 | if !p.expectPeek(token.IDENT) {
29 | return nil
30 | }
31 |
32 | stmt.Name = &ast.Identifier{Token: p.curToken, Value: p.curToken.Literal}
33 |
34 | if !p.expectPeek(token.ASSIGN) {
35 | return nil
36 | }
37 |
38 | p.nextToken()
39 |
40 | stmt.Value = p.parseExpression(LOWEST)
41 |
42 | if p.peekTokenIs(token.SEMICOLON) {
43 | p.nextToken()
44 | }
45 |
46 | return stmt
47 | }
48 |
49 | func (p *Parser) parseReturnStatement() *ast.ReturnStatement {
50 | stmt := &ast.ReturnStatement{Token: p.curToken}
51 | p.nextToken()
52 |
53 | stmt.ReturnValue = p.parseExpression(LOWEST)
54 |
55 | if p.peekTokenIs(token.SEMICOLON) {
56 | p.nextToken()
57 | }
58 |
59 | return stmt
60 | }
61 |
62 | func (p *Parser) parseBlockStatement() *ast.BlockStatement {
63 | block := &ast.BlockStatement{Token: p.curToken}
64 | block.Statements = []ast.Statement{}
65 |
66 | p.nextToken()
67 |
68 | for !p.curTokenIs(token.RBRACE) {
69 | if p.curTokenIs(token.EOF) {
70 | msg := fmt.Sprintf("Mstari %d: Hukufunga Mabano '}'", p.curToken.Line)
71 | p.errors = append(p.errors, msg)
72 | return nil
73 | }
74 | stmt := p.parseStatement()
75 | block.Statements = append(block.Statements, stmt)
76 | p.nextToken()
77 | }
78 |
79 | return block
80 | }
81 |
--------------------------------------------------------------------------------
/parser/string.go:
--------------------------------------------------------------------------------
1 | package parser
2 |
3 | import (
4 | "github.com/NuruProgramming/Nuru/ast"
5 | )
6 |
7 | func (p *Parser) parseStringLiteral() ast.Expression {
8 | return &ast.StringLiteral{Token: p.curToken, Value: p.curToken.Literal}
9 | }
10 |
--------------------------------------------------------------------------------
/parser/switch.go:
--------------------------------------------------------------------------------
1 | package parser
2 |
3 | import (
4 | "fmt"
5 |
6 | "github.com/NuruProgramming/Nuru/ast"
7 | "github.com/NuruProgramming/Nuru/token"
8 | )
9 |
10 | func (p *Parser) parseSwitchStatement() ast.Expression {
11 | expression := &ast.SwitchExpression{Token: p.curToken}
12 |
13 | if !p.expectPeek(token.LPAREN) {
14 | return nil
15 | }
16 |
17 | p.nextToken()
18 | expression.Value = p.parseExpression(LOWEST)
19 |
20 | if expression.Value == nil {
21 | return nil
22 | }
23 |
24 | if !p.expectPeek(token.RPAREN) {
25 | return nil
26 | }
27 |
28 | if !p.expectPeek(token.LBRACE) {
29 | return nil
30 | }
31 | p.nextToken()
32 |
33 | for !p.curTokenIs(token.RBRACE) {
34 |
35 | if p.curTokenIs(token.EOF) {
36 | msg := fmt.Sprintf("Mstari %d: Haukufunga ENDAPO (SWITCH)", p.curToken.Line)
37 | p.errors = append(p.errors, msg)
38 | return nil
39 | }
40 | tmp := &ast.CaseExpression{Token: p.curToken}
41 |
42 | if p.curTokenIs(token.DEFAULT) {
43 |
44 | tmp.Default = true
45 |
46 | } else if p.curTokenIs(token.CASE) {
47 |
48 | p.nextToken()
49 |
50 | if p.curTokenIs(token.DEFAULT) {
51 | tmp.Default = true
52 | } else {
53 | tmp.Expr = append(tmp.Expr, p.parseExpression(LOWEST))
54 | for p.peekTokenIs(token.COMMA) {
55 | p.nextToken()
56 | p.nextToken()
57 | tmp.Expr = append(tmp.Expr, p.parseExpression(LOWEST))
58 | }
59 | }
60 | } else {
61 | msg := fmt.Sprintf("Mstari %d: Tulitegemea Kauli IKIWA (CASE) au KAWAIDA (DEFAULT) lakini tumepewa: %s", p.curToken.Line, p.curToken.Type)
62 | p.errors = append(p.errors, msg)
63 | return nil
64 | }
65 |
66 | if !p.expectPeek(token.LBRACE) {
67 | return nil
68 | }
69 |
70 | tmp.Block = p.parseBlockStatement()
71 | p.nextToken()
72 | expression.Choices = append(expression.Choices, tmp)
73 | }
74 |
75 | count := 0
76 | for _, c := range expression.Choices {
77 | if c.Default {
78 | count++
79 | }
80 | }
81 | if count > 1 {
82 | msg := fmt.Sprintf("Kauli ENDAPO (SWITCH) hua na kauli 'KAWAIDA' (DEFAULT) moja tu! Wewe umeweka %d", count)
83 | p.errors = append(p.errors, msg)
84 | return nil
85 |
86 | }
87 | return expression
88 |
89 | }
90 |
--------------------------------------------------------------------------------
/parser/while.go:
--------------------------------------------------------------------------------
1 | package parser
2 |
3 | import (
4 | "github.com/NuruProgramming/Nuru/ast"
5 | "github.com/NuruProgramming/Nuru/token"
6 | )
7 |
8 | func (p *Parser) parseWhileExpression() ast.Expression {
9 | expression := &ast.WhileExpression{Token: p.curToken}
10 |
11 | if !p.expectPeek(token.LPAREN) {
12 | return nil
13 | }
14 |
15 | p.nextToken()
16 | expression.Condition = p.parseExpression(LOWEST)
17 |
18 | if !p.expectPeek(token.RPAREN) {
19 | return nil
20 | }
21 |
22 | if !p.expectPeek(token.LBRACE) {
23 | return nil
24 | }
25 |
26 | expression.Consequence = p.parseBlockStatement()
27 |
28 | return expression
29 | }
30 |
--------------------------------------------------------------------------------
/repl/docs/en/arrays.md:
--------------------------------------------------------------------------------
1 | # Arrays in Nuru
2 |
3 | Arrays in Nuru are versatile data structures that can hold multiple items, including different types such as numbers, strings, booleans, functions, and null values. This page covers various aspects of arrays, including how to create, manipulate, and iterate over them using Nuru's built-in keywords and methods.
4 |
5 | ## Creating Arrays
6 |
7 | To create an array, use square brackets [] and separate items with commas:
8 |
9 | ```s
10 | orodha = [1, "pili", kweli]
11 | ```
12 | ## Accessing and Modifying Array Elements
13 |
14 | Arrays in Nuru are zero-indexed. To access an element, use the element's index in square brackets:
15 |
16 | ```s
17 | namba = [10, 20, 30]
18 | jina = namba[1] // jina is 20
19 | ```
20 |
21 | You can reassign an element in an array using its index:
22 |
23 | ```s
24 | namba[1] = 25
25 | ```
26 |
27 | ## Concatenating Arrays
28 |
29 | To concatenate two or more arrays, use the + operator:
30 |
31 | ```s
32 | a = [1, 2, 3]
33 | b = [4, 5, 6]
34 | c = a + b
35 | // c is now [1, 2, 3, 4, 5, 6]
36 | ```
37 |
38 | ## Checking for Array Membership
39 |
40 | Use the `ktk` keyword to check if an item exists in an array:
41 |
42 | ```s
43 | namba = [10, 20, 30]
44 | andika(20 ktk namba) // will print kweli
45 | ```
46 |
47 | ## Looping Over Arrays
48 |
49 | You can use the kwa and ktk keywords to loop over array elements. To loop over just the values, use the following syntax:
50 |
51 | ```
52 | namba = [1, 2, 3, 4, 5]
53 |
54 | kwa thamani ktk namba {
55 | andika(thamani)
56 | }
57 | ```
58 |
59 | To loop over both index and value pairs, use this syntax:
60 |
61 | ```s
62 | majina = ["Juma", "Asha", "Haruna"]
63 |
64 | kwa idx, jina ktk majina {
65 | andika(idx, "-", jina)
66 | }
67 | ```
68 |
69 | ## Array Methods
70 |
71 | Arrays in Nuru have several built-in methods:
72 |
73 | ### idadi()
74 |
75 | idadi() returns the length of an array:
76 |
77 | ```s
78 | a = [1, 2, 3]
79 | urefu = a.idadi()
80 | andika(urefu) // will print 3
81 | ```
82 |
83 | ### sukuma()
84 |
85 | sukuma() adds one or more items to the end of an array:
86 |
87 | ```s
88 | a = [1, 2, 3]
89 | a.sukuma("s", "g")
90 | andika(a) // will print [1, 2, 3, "s", "g"]
91 | ```
92 |
93 | ### yamwisho()
94 |
95 | yamwisho() returns the last item in an array, or tupu if the array is empty:
96 |
97 | ```s
98 | a = [1, 2, 3]
99 | mwisho = a.yamwisho()
100 | andika(mwisho) // will print 3
101 |
102 | b = []
103 | mwisho = b.yamwisho()
104 | andika(mwisho) // will print tupu
105 | ```
106 |
107 | ### map()
108 |
109 | map() goes through every element in the array and applies the passed function to each element. It will then return a new array with the updated elements:
110 | ```s
111 | a = [1, 2, 3]
112 |
113 | b = a.map(unda(x){rudisha x*2})
114 |
115 | andika(b) // [2, 4, 6]
116 | ```
117 |
118 | ### chuja()
119 |
120 | chuja() will go through every single element of an array and checks if that element returns true or false when passed into a function. It will return a new array with elements that returned true:
121 | ```s
122 | a = [1, 2, 3, 4]
123 |
124 | b = a.chuja(unda(x){
125 | kama (x % 2 == 0)
126 | {rudisha kweli}
127 | rudisha sikweli
128 | })
129 |
130 | andika(b) // [2, 4]
131 | ```
132 |
133 | With this information, you can now effectively work with arrays in Nuru, making it easy to manipulate collections of data in your programs.
134 |
--------------------------------------------------------------------------------
/repl/docs/en/bool.md:
--------------------------------------------------------------------------------
1 | # Working with Booleans in Nuru
2 |
3 | Boolean objects in Nuru are truthy, meaning that any value is true, except tupu and sikweli. They are used to evaluate expressions that return true or false values.
4 |
5 | ## Evaluating Boolean Expressions
6 |
7 | ### Evaluating Simple Expressions
8 |
9 | In Nuru, you can evaluate simple expressions that return a boolean value:
10 |
11 | ```s
12 | andika(1 > 2) // Output: `sikweli`
13 |
14 | andika(1 + 3 < 10) // Output: `kweli`
15 | ```
16 |
17 | ### Evaluating Complex Expressions
18 |
19 | In Nuru, you can use boolean operators to evaluate complex expressions:
20 |
21 | ```s
22 | a = 5
23 | b = 10
24 | c = 15
25 |
26 | result = (a < b) && (b < c)
27 |
28 | kama (result) {
29 | andika("Both conditions are true")
30 | } sivyo {
31 | andika("At least one condition is false")
32 | }
33 | // Output: "Both conditions are true"
34 | ```
35 |
36 | Here, we create three variables a, b, and c. We then evaluate the expression (a < b) && (b < c). Since both conditions are true, the output will be "Both conditions are true".
37 |
38 | ## Boolean Operators
39 |
40 | Nuru has several boolean operators that you can use to evaluate expressions:
41 |
42 | ### The && Operator
43 |
44 | The && operator evaluates to true only if both operands are true. Here's an example:
45 |
46 | ```s
47 | andika(kweli && kweli) // Output: `kweli`
48 |
49 | andika(kweli && sikweli) // Output: `sikweli`
50 | ```
51 |
52 | ### The || Operator
53 |
54 | The || operator evaluates to true if at least one of the operands is true. Here's an example:
55 |
56 | ```s
57 | andika(kweli || sikweli) // Output: `kweli`
58 |
59 | andika(sikweli || sikweli) // Output: `sikweli`
60 | ```
61 |
62 | ### The ! Operator
63 |
64 | The ! operator negates the value of the operand. Here's an example:
65 |
66 | ```s
67 | andika(!kweli) // Output: `sikweli`
68 |
69 | andika(!sikweli) // Output: `kweli`
70 | ```
71 |
72 | ## Working with Boolean Values in Loops
73 |
74 | In Nuru, you can use boolean expressions in loops to control their behavior. Here's an example:
75 |
76 | ```s
77 | namba = [1, 2, 3, 4, 5]
78 |
79 | kwa thamani ktk namba {
80 | kama (thamani % 2 == 0) {
81 | andika(thamani, "is even")
82 | } sivyo {
83 | andika(thamani, "is odd")
84 | }
85 | }
86 | // Output:
87 | // 1 is odd
88 | // 2 is even
89 | // 3 is odd
90 | // 4 is even
91 | // 5 is odd
92 | ```
93 |
94 | Here, we create an array namba with the values 1 through 5. We then loop over each value in the array and use the % operator to determine if it is even or odd. The output will be "is even" for even numbers and "is odd" for odd numbers.
95 |
96 |
97 | Boolean objects in Nuru can be used to evaluate expressions that return true or false values. You can use boolean operators to evaluate complex expressions and control the behavior of loops. Understanding how to work with boolean values is an essential skill for any Nuru programmer.
--------------------------------------------------------------------------------
/repl/docs/en/builtins.md:
--------------------------------------------------------------------------------
1 | # Built-in Functions in Nuru
2 |
3 | Nuru has several built-in functions that perform specific tasks.
4 |
5 | ## The andika() Function
6 |
7 | The andika() function is used to print out messages to the console. It can take zero or more arguments, and the arguments will be printed out with a space in between them. Additionally, andika() supports basic formatting such as /n for a new line, /t for a tab space, and \\ for a backslash. Here's an example:
8 |
9 | ```s
10 | andika(1, 2, 3) // Output: "1 2 3"
11 | ```
12 |
13 | ## The jaza() Function
14 |
15 | The jaza() function is used to get input from the user. It can take zero or one argument, which is a string that will be used as a prompt for the user. Here's an example:
16 |
17 | ```s
18 | fanya salamu = unda() {
19 | fanya jina = jaza("Unaitwa nani? ")
20 | andika("Mambo vipi", jina)
21 | }
22 |
23 | salamu()
24 | ```
25 |
26 | In this example, we define a function `salamu()` that prompts the user to enter their name using the `jaza()` function. We then use the `andika()` function to print out a message that includes the user's name.
27 |
28 | ## The aina() Function
29 |
30 | The `aina()` function is used to determine the type of an object. It accepts one argument, and the return value will be a string indicating the type of the object. Here's an example:
31 |
32 | ```s
33 | aina(2) // Output: "NAMBA"
34 | aina("Nuru") // Output: "NENO"
35 | ```
36 |
37 | ## The fungua() Function
38 |
39 | The `fungua()` function is used to open a file. It accepts one argument, which is the path to the file that you want to open. Here's an example:
40 |
41 | ```s
42 | faili = fungua("data.txt")
43 | ```
44 |
45 | In this example, we use the `fungua()` function to open a file named "data.txt". The variable faili will contain a reference to the opened file.
--------------------------------------------------------------------------------
/repl/docs/en/comments.md:
--------------------------------------------------------------------------------
1 | # Comments in Nuru
2 |
3 | In Nuru, you can write comments to provide explanations and documentation for your code. Comments are lines of text that are ignored by the Nuru interpreter, so they will not affect the behavior of your program. There are two types of comments in Nuru: single-line comments and multi-line comments.
4 |
5 | ## Single-Line Comments
6 |
7 | Single-line comments are used to provide brief explanations or documentation for a single line of code. To write a single-line comment in Nuru, use two forward slashes (//) followed by your comment text. Here's an example:
8 |
9 | ```s
10 | // This line will be ignored by the Nuru interpreter
11 | ```
12 |
13 | In this example, the comment text "This line will be ignored by the Nuru interpreter" will be ignored by the interpreter, so it will not affect the behavior of the program.
14 |
15 | ## Multi-Line Comments
16 |
17 | Multi-line comments are used to provide more detailed explanations or documentation for multiple lines of code. To write a multi-line comment in Nuru, use a forward slash followed by an asterisk ( /* ) to start the comment, and an asterisk followed by a forward slash ( */ ) to end the comment. Here's an example:
18 |
19 | ```s
20 | /*
21 | These lines
22 | Will
23 | be
24 | ignored
25 | */
26 | ```
27 |
28 | In this example, all the lines between the /* and */ symbols will be ignored by the Nuru interpreter, so they will not affect the behavior of the program.
29 |
30 | By utilizing single-line and multi-line comments in Nuru, you can make your code more readable and easier to maintain for yourself and others who may need to work with your code in the future.
--------------------------------------------------------------------------------
/repl/docs/en/dictionaries.md:
--------------------------------------------------------------------------------
1 | # Dictionaries in Nuru
2 |
3 | Dictionaries in Nuru, also known as "kamusi," are powerful and flexible data structures that store key-value pairs. This page provides a comprehensive overview of dictionaries in Nuru, including how to create, access, modify, and iterate over them.
4 |
5 | ## Creating Dictionaries
6 |
7 | Dictionaries are enclosed in curly braces {} and consist of keys and values separated by colons. Here's an example of defining a dictionary:
8 |
9 | ```s
10 |
11 | orodha = {"jina": "Juma", "umri": 25}
12 | ```
13 |
14 | Keys can be strings, integers, floats, or booleans, while values can be any data type, including strings, integers, floats, booleans, null, or functions:
15 |
16 | ```s
17 | k = {
18 | "jina": "Juma",
19 | "umri": 25,
20 | kweli: "kweli",
21 | "salimu": unda(x) { andika("habari", x) },
22 | "sina value": tupu
23 | }
24 | ```
25 |
26 | ## Accessing Elements
27 |
28 | Access individual elements in a dictionary using their keys:
29 |
30 | ```s
31 |
32 | andika(k[kweli]) // kweli
33 | andika(k["salimu"]("Juma")) // habari Juma
34 | ```
35 |
36 | ## Updating Elements
37 |
38 | Update the value of an element by assigning a new value to its key:
39 |
40 | ```s
41 | k['umri'] = 30
42 | andika(k['umri']) // 30
43 | ```
44 |
45 | ## Adding New Elements
46 |
47 | Add a new key-value pair to a dictionary by assigning a value to a non-existent key:
48 |
49 | ```s
50 | k["lugha"] = "Kiswahili"
51 | andika(k["lugha"]) // Kiswahili
52 | ```
53 |
54 | ## Concatenating Dictionaries
55 |
56 | Combine two dictionaries using the + operator:
57 |
58 | ```s
59 | matunda = {"a": "apple", "b": "banana"}
60 | mboga = {"c": "carrot", "d": "daikon"}
61 | vyakula = matunda + mboga
62 | andika(vyakula) // {"a": "apple", "b": "banana", "c": "carrot", "d": "daikon"}
63 | ```
64 |
65 | ## Checking If a Key Exists in a Dictionary
66 |
67 | Use the ktk keyword to check if a key exists in a dictionary:
68 |
69 | ```s
70 |
71 | "umri" ktk k // kweli
72 | "urefu" ktk k // sikweli
73 | ```
74 |
75 | ## Looping Over a Dictionary
76 |
77 | Loop over a dictionary to access its keys and values:
78 |
79 | ```s
80 |
81 | hobby = {"a": "asili", "b": "baiskeli", "c": "chakula"}
82 | kwa i, v ktk hobby {
83 | andika(i, "=>", v)
84 | }
85 | ```
86 | Output
87 | ```s
88 | a => asili
89 | b => baiskeli
90 | c => chakula
91 | ```
92 |
93 | Loop over just the values:
94 |
95 | ```s
96 | kwa v ktk hobby {
97 | andika(v)
98 | }
99 | ```
100 | Output
101 | ```s
102 | asili
103 | baiskeli
104 | chakula
105 | ```
106 |
107 | With this knowledge, you can now effectively use dictionaries in Nuru to store and manage key-value pairs, offering a flexible way to organize and access data in your programs.
--------------------------------------------------------------------------------
/repl/docs/en/files.md:
--------------------------------------------------------------------------------
1 | # Files in Nuru
2 |
3 | Nuru's ability to deal with files is primitive, and as for now it only allows you to read contents of a file.
4 |
5 | ## Opening a File
6 |
7 | You open a file with the `fungua` keyword. This will return an object of type `FAILI`:
8 | ```
9 | fileYangu = fungua("file.txt")
10 |
11 | aina(fileYangu) // FAILI
12 | ```
13 |
14 | ## Reading a File
15 |
16 | Once you have a file object you can read its contents with the `soma()` method. This will return the contents of the file as a string:
17 | ```
18 | fileYangu = fungua("file.txt")
19 |
20 | fileYangu.soma()
21 | ```
22 |
--------------------------------------------------------------------------------
/repl/docs/en/for.md:
--------------------------------------------------------------------------------
1 | # For Loops in Nuru
2 |
3 | For loops are a fundamental control structure in Nuru, used for iterating over iterable objects such as strings, arrays, and dictionaries. This page covers the syntax and usage of for loops in Nuru, including key-value pair iteration, and the use of break and continue statements.
4 |
5 | ## Basic Syntax
6 | To create a for loop, use the kwa keyword followed by a temporary identifier (such as i or v) and the iterable object. Enclose the loop body in curly braces {}. Here's an example with a string:
7 |
8 | ```s
9 | jina = "lugano"
10 |
11 | kwa i ktk jina {
12 | andika(i)
13 | }
14 | ```
15 | Output:
16 |
17 | ```s
18 | l
19 | u
20 | g
21 | a
22 | n
23 | o
24 | ```
25 |
26 | ## Iterating Over Key-Value Pairs
27 |
28 | ### Dictionaries
29 |
30 | Nuru allows you to iterate over both the value or the key-value pair of an iterable. To iterate over just the values, use one temporary identifier:
31 |
32 | ```s
33 | kamusi = {"a": "andaa", "b": "baba"}
34 |
35 | kwa v ktk kamusi {
36 | andika(v)
37 | }
38 | ```
39 |
40 | Output:
41 |
42 | ```s
43 | andaa
44 | baba
45 | ```
46 | To iterate over both the keys and the values, use two temporary identifiers:
47 |
48 | ```s
49 |
50 | kwa k, v ktk kamusi {
51 | andika(k + " ni " + v)
52 | }
53 | ```
54 | Output:
55 |
56 | ```s
57 | a ni andaa
58 | b ni baba
59 | ```
60 |
61 | ### Strings
62 |
63 | To iterate over just the values in a string, use one temporary identifier:
64 |
65 | ```s
66 | kwa v ktk "mojo" {
67 | andika(v)
68 | }
69 | ```
70 |
71 | Output:
72 | ```s
73 | m
74 | o
75 | j
76 | o
77 | ```
78 | To iterate over both the keys and the values in a string, use two temporary identifiers:
79 |
80 | ```s
81 | kwa i, v ktk "mojo" {
82 | andika(i, "->", v)
83 | }
84 | ```
85 | Output:
86 | ```s
87 | 0 -> m
88 | 1 -> o
89 | 2 -> j
90 | 3 -> o
91 | ```
92 |
93 | ### Lists
94 |
95 | To iterate over just the values in a list, use one temporary identifier:
96 |
97 | ```s
98 | majina = ["juma", "asha", "haruna"]
99 |
100 | kwa v ktk majina {
101 | andika(v)
102 | }
103 | ```
104 |
105 | Output:
106 |
107 | ```s
108 | juma
109 | asha
110 | haruna
111 | ```
112 |
113 | To iterate over both the keys and the values in a list, use two temporary identifiers:
114 |
115 | ```s
116 | kwa i, v ktk majina {
117 | andika(i, "-", v)
118 | }
119 | ```
120 |
121 | Output:
122 |
123 | ```s
124 | 0 - juma
125 | 1 - asha
126 | 2 - haruna
127 | ```
128 |
129 | ## Break (Vunja) and Continue (Endelea)
130 |
131 | ### Break (Vunja)
132 |
133 | Use the vunja keyword to terminate a loop:
134 |
135 | ```s
136 |
137 | kwa i, v ktk "mojo" {
138 | kama (i == 2) {
139 | andika("nimevunja")
140 | vunja
141 | }
142 | andika(v)
143 | }
144 | ```
145 |
146 | Output:
147 |
148 | ```s
149 | m
150 | o
151 | nimevunja
152 | ```
153 |
154 | ### Continue (Endelea)
155 |
156 | Use the endelea keyword to skip a specific iteration:
157 |
158 | ```s
159 | kwa i, v ktk "mojo" {
160 | kama (i == 2) {
161 | andika("nimeruka")
162 | endelea
163 | }
164 | andika(v)
165 | }
166 | ```
167 |
168 | Output:
169 |
170 | ```s
171 | m
172 | o
173 | nimeruka
174 | o
175 | ```
--------------------------------------------------------------------------------
/repl/docs/en/function.md:
--------------------------------------------------------------------------------
1 | # Functions in Nuru
2 |
3 | Functions are a fundamental part of Nuru programming, allowing you to define reusable blocks of code. This page covers the syntax and usage of functions in Nuru, including parameters, default parameters, return statements, recursion, and closures.
4 |
5 | ## Basic Syntax
6 |
7 | A function block starts with the unda keyword, followed by parameters enclosed in parentheses () and the body enclosed in curly braces {}. Functions must be assigned to a variable:
8 |
9 | ```s
10 | jum = unda(x, y) {
11 | rudisha x + y
12 | }
13 |
14 | jum(2, 3) // 5
15 | ```
16 |
17 | ## Parameters
18 |
19 | Functions can have zero or any number of arguments. Arguments can be of any type, even other functions:
20 |
21 | ```s
22 | salamu = unda() {
23 | andika("Habari yako")
24 | }
25 |
26 | salamu()
27 |
28 | salamu = unda(jina) {
29 | andika("Habari yako", jina)
30 | }
31 |
32 | salamu("asha") // Habari yako asha
33 | ```
34 |
35 | ## Default Parameters
36 |
37 | Functions can be provided with default parameters:
38 |
39 | ```s
40 | salimu = unda(salamu="Habari") {
41 | andika(salamu)
42 | }
43 |
44 | salimu() // Habari
45 | salimu("Mambo") // Mambo
46 | ```
47 |
48 | ## Return (rudisha)
49 |
50 | You can return values with the rudisha keyword. The rudisha keyword will terminate the block and return the value:
51 |
52 | ```s
53 | mfano = unda(x) {
54 | rudisha "nimerudi"
55 | andika(x)
56 | }
57 |
58 | mfano("x") // nimerudi
59 | ```
60 |
61 | ## Recursion
62 |
63 | Nuru also supports recursion. Here's an example of a recursive Fibonacci function:
64 |
65 | ```s
66 |
67 | fib = unda(n) {
68 | kama (n <= 1) {
69 | rudisha n
70 | } sivyo {
71 | rudisha fib(n-1) + fib(n-2)
72 | }
73 | }
74 |
75 | andika(fib(10)) // 55
76 | ```
77 |
78 | The fib function calculates the nth Fibonacci number by recursively calling itself with n-1 and n-2 as arguments until n is less than or equal to 1.
79 |
80 | ## Closures
81 |
82 | Closures are anonymous functions that can capture and store references to variables from their surrounding context. In Nuru, you can create closures using the unda keyword without assigning them to a variable. Here's an example:
83 |
84 | ```s
85 | fanya jum = unda(x) {
86 | rudisha unda(y) {
87 | rudisha x + y
88 | }
89 | }
90 |
91 | fanya jum_x = jum(5)
92 | andika(jum_x(3)) // 8
93 | ```
94 |
95 | In the example above, the jum function returns another function that takes a single parameter y. The returned function has access to the x variable from its surrounding context.
96 |
97 | Now that you understand the basics of functions in Nuru, including recursion and closures, you can create reusable blocks of code to simplify your programs and improve code organization.
--------------------------------------------------------------------------------
/repl/docs/en/identifiers.md:
--------------------------------------------------------------------------------
1 | # Identifiers in Nuru
2 |
3 | Identifiers are used to name variables, functions, and other elements in your Nuru code. This page covers the rules and best practices for creating identifiers in Nuru.
4 |
5 | ## Syntax Rules
6 |
7 | Identifiers can contain letters, numbers, and underscores. However, there are a few rules you must follow when creating identifiers:
8 | - Identifiers cannot start with a number.
9 | - Identifiers are case-sensitive. For example, myVar and myvar are considered distinct identifiers.
10 |
11 | Here are some examples of valid identifiers:
12 |
13 | ```s
14 | fanya birth_year = 2020
15 | andika(birth_year) // 2020
16 |
17 | fanya convert_c_to_p = "C to P"
18 | andika(convert_c_to_p) // "C to P"
19 | ```
20 |
21 | In the examples above, birth_year and convert_c_to_p are both valid identifiers.
22 |
23 | ## Best Practices
24 |
25 | When choosing identifiers, it's important to follow best practices to ensure your code is clear and easy to understand:
26 |
27 | - Use descriptive names that clearly indicate the purpose or meaning of the variable or function.
28 | - Follow a consistent naming convention, such as camelCase (myVariableName) or snake_case (my_variable_name).
29 | - Avoid using single-letter variable names, except for commonly accepted cases like loop counters (i, j, k).
30 |
31 | By following these best practices when creating identifiers, you will make your Nuru code more readable and maintainable for yourself and others.
32 |
--------------------------------------------------------------------------------
/repl/docs/en/ifStatements.md:
--------------------------------------------------------------------------------
1 | # Conditional Statements in Nuru
2 |
3 | Conditional statements in Nuru are used to perform different actions based on different conditions. The if/else statement is a fundamental control structure that allows you to execute code based on specific conditions. This page covers the basics of if/else statements in Nuru.
4 |
5 | ## If Statement (Kama)
6 |
7 | An if statement starts with the kama keyword, followed by a condition in parentheses (). If the condition is true, the code inside the curly braces {} will be executed.
8 |
9 | ```s
10 | kama (2 > 1) {
11 | andika(kweli) // kweli
12 | }
13 | ```
14 |
15 | In this example, the condition 2 > 1 is true, so the andika(kweli) statement is executed, and the output is kweli.
16 |
17 | ## Else If and Else Blocks (Au Kama and Sivyo)
18 |
19 | You can use au kama to test multiple conditions and sivyo to specify a default block of code to be executed when none of the conditions are true.
20 |
21 | ```s
22 |
23 | fanya a = 10
24 |
25 | kama (a > 100) {
26 | andika("a imezidi 100")
27 | } au kama (a < 10) {
28 | andika("a ndogo kuliko 10")
29 | } sivyo {
30 | andika("Thamani ya a ni", a)
31 | }
32 |
33 | // The output will be 'Thamani ya a ni 10'
34 | ```
35 |
36 | In this example, the first condition a > 100 is false, and the second condition a < 10 is also false. Therefore, the code inside the sivyo block is executed, and the output is 'Thamani ya a ni 10'.
37 |
38 | By using if/else statements with the kama, au kama, and sivyo keywords, you can control the flow of your Nuru code based on different conditions.
--------------------------------------------------------------------------------
/repl/docs/en/json.md:
--------------------------------------------------------------------------------
1 | # JSON in Nuru
2 |
3 | Nuru also makes it easy to deal with JSON.
4 |
5 | ## Import JSONI
6 |
7 | Use the following to import the json module:
8 | ```
9 | tumia jsoni
10 | ```
11 |
12 | ## Decoding JSON with dikodi()
13 | Use this to convert a string to a dictionary:
14 | ```
15 | jsonString = '{
16 | "error": false,
17 | "category": "Pun",
18 | "type": "single",
19 | "joke": "I was reading a great book about an immortal dog the other day. It was impossible to put down."
20 | }'
21 |
22 | // to make it a dict
23 |
24 | tumia jsoni
25 |
26 | k = jsoni.dikodi(jsonString)
27 |
28 | k["joke"] // I was reading a great book about an immortal dog the other day. It was impossible to put down.
29 | ```
30 |
31 | ## Encoding JSON with enkodi()
32 |
33 | You can encode JSON with the `enkodi` method, this will turn a dictionary to a string:
34 | ```
35 | tumia jsoni
36 |
37 | k = {
38 | "a": "apple",
39 | "b": "banana"
40 | }
41 |
42 | j = json.enkodi(k)
43 | ```
44 |
--------------------------------------------------------------------------------
/repl/docs/en/keywords.md:
--------------------------------------------------------------------------------
1 | # KEYWORDS
2 |
3 | Keywords in Nuru are reserved words that have special meanings and cannot be used as identifiers for variables, functions, or classes. This page covers the syntax and usage of keywords in Nuru, including reserved keywords and built-in functions.
4 |
5 | ## Reserved Keywords
6 |
7 | The table below lists the reserved keywords in Nuru. These words have specific meanings in the language and cannot be used as identifiers:
8 |
9 |
10 |
11 |
12 | kweli |
13 | sikweli |
14 | unda |
15 | fanya |
16 |
17 |
18 | kama |
19 | au |
20 | sivyo |
21 | wakati |
22 |
23 |
24 | rudisha |
25 | vunja |
26 | endelea |
27 | tupu |
28 |
29 |
30 | ktk |
31 | kwa |
32 | badili |
33 | ikiwa |
34 |
35 |
36 | kawaida |
37 | |
38 | |
39 | |
40 |
41 |
42 |
43 |
44 | ## BuiltIns
45 |
46 | Nuru also provides several built-in functions that are reserved and cannot be used as identifiers. These functions offer essential functionalities for common tasks in the language:
47 |
48 |
49 |
50 |
51 | andika |
52 | aina |
53 | jaza |
54 | fungua |
55 |
56 |
57 |
58 |
59 | Understanding the keywords and built-in functions in Nuru is essential for writing clear, concise, and error-free code. By respecting the reserved words and their specific meanings, you can create more robust and maintainable programs in Nuru.
--------------------------------------------------------------------------------
/repl/docs/en/net.md:
--------------------------------------------------------------------------------
1 | # HTTP with Nuru
2 |
3 | You can access the internet via http protocol using the `mtandao` module.
4 |
5 | ## Importing
6 |
7 | Import the module with:
8 | ```
9 | tumia mtandao
10 | ```
11 |
12 | ## Methods
13 |
14 | ### peruzi()
15 |
16 | Use this as GET method. It can either accept one positional argument which will be the URL:
17 |
18 | ```
19 | tumia mtandao
20 |
21 | mtandao.peruzi("http://google.com")
22 | ```
23 |
24 | Or you can use keyword arguments to pass in parameters and headers as shown below. Note that headers and parameters must be a dictionary:
25 |
26 | ```
27 | tumia mtandao
28 |
29 | url = "http://mysite.com"
30 | headers = {"Authentication": "Bearer XXXX"}
31 |
32 | mtandao.peruzi(yuareli=url, vichwa=headers, mwili=params)
33 | ```
34 |
35 | ### tuma()
36 |
37 | Use this as POST method. Use keyword arguments to pass in parameters and headers as shown below. Note that headers and parameters must be a dictionary:
38 |
39 | ```
40 | tumia mtandao
41 |
42 | url = "http://mysite.com"
43 | headers = {"Authentication": "Bearer XXXX"}
44 | params = {"key": "Value"}
45 |
46 | mtandao.tuma(yuareli=url, vichwa=headers, mwili=params)
47 | ```
48 |
--------------------------------------------------------------------------------
/repl/docs/en/null.md:
--------------------------------------------------------------------------------
1 | # Null (Tupu) in Nuru
2 |
3 | The null data type in Nuru represents the absence of a value or the concept of "nothing" or "empty." This page covers the syntax and usage of the null data type in Nuru, including its definition and evaluation.
4 |
5 | ## Definition
6 |
7 | A null data type is a data type with no value, defined with the tupu keyword:
8 |
9 | ```s
10 | fanya a = tupu
11 | ```
12 | ## Evaluation
13 |
14 | When evaluating a null data type in a conditional expression, it will evaluate to false:
15 |
16 | ```s
17 | kama (a) {
18 | andika("niko tupu")
19 | } sivyo {
20 | andika("nimevaa nguo")
21 | }
22 |
23 | // Output: nimevaa nguo
24 | ```
25 |
26 | The null data type is useful in Nuru when you need to represent an uninitialized, missing, or undefined value in your programs. By understanding the null data type, you can create more robust and flexible code.
--------------------------------------------------------------------------------
/repl/docs/en/numbers.md:
--------------------------------------------------------------------------------
1 | # INTEGERS (NAMBA) AND FLOATS (DESIMALI)
2 |
3 | Integers and floats are the basic numeric data types in Nuru, used for representing whole numbers and decimal numbers, respectively. This page covers the syntax and usage of integers and floats in Nuru, including precedence, unary increments, shorthand assignments, and negative numbers.
4 |
5 | ## PRECEDENCE
6 |
7 | Integers and floats behave as expected in mathematical operations, following the BODMAS rule:
8 | ```go
9 | 2 + 3 * 5 // 17
10 |
11 | fanya a = 2.5
12 | fanya b = 3/5
13 |
14 | a + b // 2.8
15 | ```
16 |
17 | ## UNARY INCREMENTS
18 |
19 | You can perform unary increments (++ and --) on both floats and integers. These will add or subtract 1 from the current value. Note that the float or int have to be assigned to a variable for this operation to work. Here's an example:
20 |
21 | ```go
22 | fanya i = 2.4
23 |
24 | i++ // 3.4
25 | ```
26 |
27 | ## SHORTHAND ASSIGNMENT
28 |
29 | Nuru supports shorthand assignments with +=, -=, /=, *=, and %=:
30 | You
31 | ```go
32 | fanya i = 2
33 |
34 | i *= 3 // 6
35 | i /= 2 // 3
36 | i += 100 // 103
37 | i -= 10 // 93
38 | i %= 90 // 3
39 | ```
40 |
41 | ## NEGATIVE NUMBERS
42 |
43 | Negative numbers also behave as expected:
44 |
45 | ```go
46 | fanya i = -10
47 |
48 | wakati (i < 0) {
49 | andika(i)
50 | i++
51 | }
52 |
53 | ```
54 | Output:
55 | ```s
56 | -10
57 | -9
58 | -8
59 | -7
60 | -6
61 | -5
62 | -4
63 | -3
64 | -2
65 | -1
66 | 0
67 | 1
68 | 2
69 | 3
70 | 4
71 | 5
72 | 6
73 | 7
74 | 8
75 | 9
76 | ```
77 |
--------------------------------------------------------------------------------
/repl/docs/en/operators.md:
--------------------------------------------------------------------------------
1 | # OPERATORS
2 | Operators are the foundation of any programming language, allowing you to perform various operations on variables and values. This page covers the syntax and usage of operators in Nuru, including assignment, arithmetic, comparison, member, and logic operators.
3 |
4 | ## ASSIGNMENT
5 |
6 | Assuming `i` and `v` are predefined variables, Nuru supports the following assignment operators:
7 |
8 | - `i = v`: which is the regular assignment operator
9 | - `i += v`: which is the equivalent of `i = i + v`
10 | - `i -= v`: which is the equivalent of `i = i - v`
11 | - `i *= v`: which is the equivalent of `i = i * v`
12 | - `i /= v`: which is the equivalent of `i = i / v`
13 | - `i += v`: which is the equivalent of `i = i + v`
14 |
15 | For `strings`, `arrays` and `dictionaries`, the `+=` sign operator is permissible. Example:
16 | ```
17 | list1 += list2 // this is equivalent to list1 = list1 + list2
18 | ```
19 |
20 | ## ARITHMETIC OPERATORS
21 |
22 | Nuru supports the following arithmetic operators:
23 |
24 | - `+`: Additon
25 | - `-`: Subtraction
26 | - `*`: Multiplication
27 | - `/`: Division
28 | - `%`: Modulo (ie the remainder of a division)
29 | - `**`: Exponential power (eg: `2**3 = 8`)
30 |
31 | ## COMPARISON OPERATORS
32 |
33 | Nuru supports the following comparison operators:
34 |
35 | - `==`: Equal to
36 | - `!=`: Not equal to
37 | - `>`: Greater than
38 | - `>=`: Greater than or equal to
39 | - `<`: Less than
40 | - `<=`: Less than or equal to
41 |
42 | ## MEMBER OPERATOR
43 |
44 | The member operator in Nuru is `ktk`. It will check if an object exists in another object:
45 | ```go
46 | fanya majina = ['juma', 'asha', 'haruna']
47 |
48 | "haruna" ktk majina // kweli
49 | "halima" ktk majina // sikweli
50 | ```
51 |
52 | ## LOGIC OPERATORS
53 |
54 | Nuru supports the following logic operators:
55 |
56 | - `&&`: Logical `AND`. It will evaluate to true if both are true, otherwise it will evaluate to false.
57 | - `||`: Logical `OR`. It will evaluate to false if both are false, otherwise it will evaluate to true.
58 | - `!`: Logical `NOT`. It will evaluate to the opposite of a given expression.
59 |
60 | ## PRECEDENCE OF OPERATORS
61 |
62 | Operators have the following precedence, starting from the highest priority to the lowest:
63 |
64 | - `()` : Items in paranthesis have the highest priority
65 | - `!`: Negation
66 | - `%`: Modulo
67 | - `**`: Exponential power
68 | - `/, *`: Division and Multiplication
69 | - `+, +=, -, -=`: Addition and Subtraction
70 | - `>, >=, <, <=`: Comparison operators
71 | - `==, !=`: Equal or Not Equal to
72 | - `=`: Assignment Operator
73 | - `ktk`: Member Operator
74 | - `&&, ||`: Logical AND and OR
75 |
76 | Understanding operators in Nuru allows you to create complex expressions, perform calculations, and make decisions based on the values of variables.
77 |
--------------------------------------------------------------------------------
/repl/docs/en/packages.md:
--------------------------------------------------------------------------------
1 | # Packages in Nuru
2 |
3 | You can use third packages written in Nuru with the following conditions:
4 |
5 | - The package file MUST be in the same directory
6 | - The package file MUST end with `nr`
7 | - The package name and package file MUST have the same name (eg: if `pakeji hesabu` then the file name must be `hesabu.nr`)
8 | - The package must have the following structure:
9 | ```
10 | // imports if any
11 |
12 | pakeji [name of package] {
13 | andaa = unda() { // the andaa function is mandatory even if its empty
14 |
15 | }
16 | [body of package]
17 | }
18 | ```
19 | - The package must be initialized with the `andaa` keyword (see above).
20 |
21 | The `andaa` keyword is for initializing your package. This is also where you'd put your global variables. The global variables should be prefixed with `@.` Eg: `@.myGlobalVar`.
22 |
23 | A variable being globally available means that the variable can be accessed and manipulated by all other methods in the package.
24 |
25 |
26 | Below is an example Sarufi package:
27 | ```
28 | // import modules
29 | tumia mtandao
30 | tumia jsoni
31 |
32 | // package body
33 | pakeji sarufi {
34 |
35 | // initialize function
36 | andaa = unda(file) {
37 | config = fungua(file) // read passwords from json file
38 | configString = config.soma()
39 |
40 | configDict = jsoni.dikodi(configString) // convert it to a dict
41 | clientID = configDict["client_id"]
42 | clientSecret = configDict["client_secret"]
43 |
44 | // fill in params
45 | params = {"client_id": clientID, "client_secret": clientSecret}
46 |
47 | // get response
48 | resp = mtandao.tuma(yuareli="https://api.sarufi.io/api/access_token", mwili=params)
49 | tokenDict = jsoni.dikodi(resp)
50 |
51 | // extract token and make it globally available
52 | @.token = tokenDict["access_token"]
53 |
54 | // make the "Bearer " globally available
55 | @.Auth = "Bearer " + @.token
56 | }
57 |
58 | // a method to get token
59 | tokenYangu = unda() {
60 | rudisha @.token
61 | }
62 |
63 | // a method to create new chatbots.
64 | // the data should be a dict
65 | tengenezaChatbot = unda(data) {
66 | majibu = mtandao.tuma(yuareli="https://api.sarufi.io/chatbot", vichwa={"Authorization": @.Auth}, mwili = data)
67 | rudisha majibu
68 | }
69 |
70 | // a method to get all available chatbots
71 | pataChatbotZote = unda() {
72 | majibu = mtandao.peruzi(yuareli="https://api.sarufi.io/chatbots", vichwa={"Authorization": @.Auth})
73 | rudisha majibu
74 | }
75 | }
76 | ```
77 |
--------------------------------------------------------------------------------
/repl/docs/en/range.md:
--------------------------------------------------------------------------------
1 | ## Range Function (mfululizo)
2 |
3 | The `mfululizo` function generates a sequence of numbers. It can be used in loops or to create arrays of sequential numbers.
4 |
5 | ### Syntax
6 |
7 | ```go
8 | mfululizo(end)
9 | mfululizo(start, end)
10 | mfululizo(start, end, step)
11 | ```
12 |
13 | ### Parameters
14 |
15 | - `end`: The upper limit of the sequence (exclusive).
16 | - `start` (optional): The starting value of the sequence. Default is 0.
17 | - `step` (optional): The increment between each number in the sequence. Default is 1.
18 |
19 | ### Return Value
20 |
21 | Returns an array of integers.
22 |
23 | ### Examples
24 |
25 | ```go
26 | // Generate numbers from 0 to 4
27 | kwa i katika mfululizo(5) {
28 | andika(i)
29 | }
30 | // Output: 0 1 2 3 4
31 |
32 | // Generate numbers from 1 to 9
33 | kwa i katika mfululizo(1, 10) {
34 | andika(i)
35 | }
36 | // Output: 1 2 3 4 5 6 7 8 9
37 |
38 | // Generate even numbers from 0 to 8
39 | kwa i katika mfululizo(0, 10, 2) {
40 | andika(i)
41 | }
42 | // Output: 0 2 4 6 8
43 |
44 | // Generate numbers in reverse order
45 | kwa i katika mfululizo(10, 0, -1) {
46 | andika(i)
47 | }
48 | // Output: 10 9 8 7 6 5 4 3 2 1
49 | ```
50 |
51 | ### Notes
52 |
53 | - The `end` value is exclusive, meaning the sequence will stop before reaching this value.
54 | - If a negative `step` is provided, `start` should be greater than `end`.
55 | - The `step` value cannot be zero.
56 |
--------------------------------------------------------------------------------
/repl/docs/en/strings.md:
--------------------------------------------------------------------------------
1 | # Strings in Nuru
2 |
3 | Strings are a sequence of characters that can represent text in the Nuru programming language. This page covers the basics of strings, their manipulation, and some built-in methods.
4 |
5 | ## Basic Syntax
6 |
7 | Strings can be enclosed in either single quotes '' or double quotes "":
8 |
9 | ```s
10 | andika("mambo") // mambo
11 |
12 | fanya a = 'niaje'
13 |
14 | andika("mambo", a) // mambo niaje
15 | ```
16 |
17 | ## Concatenating Strings
18 |
19 | Strings can be concatenated using the + operator:
20 |
21 | ```s
22 | fanya a = "habari" + " " + "yako"
23 |
24 | andika(a) // habari yako
25 |
26 | fanya b = "habari"
27 |
28 | b += " yako"
29 |
30 | // habari yako
31 | ```
32 |
33 | You can also repeat a string n number of times using the * operator:
34 |
35 | ```s
36 | andika("mambo " * 4)
37 |
38 | // mambo mambo mambo mambo
39 |
40 | fanya a = "habari"
41 |
42 | a *= 4
43 |
44 | // habarihabarihabarihabari
45 | ```
46 |
47 | ## Looping over a String
48 |
49 | You can loop through a string using the kwa keyword:
50 |
51 | ```s
52 | fanya jina = "avicenna"
53 |
54 | kwa i ktk jina {andika(i)}
55 | ```
56 | Output
57 | ```s
58 | a
59 | v
60 | i
61 | c
62 | e
63 | n
64 | n
65 | a
66 | ```
67 |
68 | And for key-value pairs:
69 |
70 | ```s
71 | kwa i, v ktk jina {
72 | andika(i, "=>", v)
73 | }
74 | ```
75 | Output
76 | ```s
77 | 0 => a
78 | 1 => v
79 | 2 => i
80 | 3 => c
81 | 4 => e
82 | 5 => n
83 | 6 => n
84 | 7 => a
85 | ```
86 |
87 | ## Comparing Strings
88 |
89 | You can compare two strings using the == operator:
90 |
91 | ```s
92 | fanya a = "nuru"
93 |
94 | andika(a == "nuru") // kweli
95 |
96 | andika(a == "mambo") // sikweli
97 | ```
98 |
99 | ## String Methods
100 |
101 | ### idadi()
102 |
103 | You can find the length of a string using the idadi method. It does not accept any parameters.
104 |
105 | ```s
106 | fanya a = "mambo"
107 | a.idadi() // 5
108 | ```
109 |
110 | ### herufikubwa()
111 |
112 | This method converts a string to uppercase. It does not accept any parameters.
113 |
114 | ```s
115 | fanya a = "nuru"
116 | a.herufikubwa() // NURU
117 | ```
118 |
119 | ### herufindogo
120 |
121 | This method converts a string to lowercase. It does not accept any parameters.
122 |
123 | ```s
124 | fanya a = "NURU"
125 | a.herufindogo() // nuru
126 | ```
127 |
128 | ### gawa
129 |
130 | The gawa method splits a string into an array based on a specified delimiter. If no argument is provided, it will split the string according to whitespace.
131 |
132 | Example without a parameter:
133 |
134 | ```s
135 | fanya a = "nuru mambo habari"
136 | fanya b = a.gawa()
137 | andika(b) // ["nuru", "mambo", "habari"]
138 | ```
139 |
140 | Example with a parameter:
141 |
142 | ```s
143 | fanya a = "nuru,mambo,habari"
144 | fanya b = a.gawa(",")
145 | andika(b) // ["nuru", "mambo", "habari"]
146 | ```
147 |
148 | By understanding strings and their manipulation in Nuru, you can effectively work with text data in your programs.
--------------------------------------------------------------------------------
/repl/docs/en/switch.md:
--------------------------------------------------------------------------------
1 | # Switch Statements in Nuru
2 |
3 | Switch statements in Nuru allow you to execute different code blocks based on the value of a given expression. This page covers the basics of switch statements and their usage.
4 |
5 | ## Basic Syntax
6 |
7 | You initialize a switch statement with the badili keyword, the expression inside parentheses (), and all cases enclosed within curly braces {}.
8 |
9 | A case statement has the keyword ikiwa followed by a value to check. Multiple values can be in a single case separated by commas ,. The consequence to execute if a condition is fulfilled must be inside curly braces {}. Here's an example:
10 |
11 | ```s
12 | fanya a = 2
13 |
14 | badili (a){
15 | ikiwa 3 {
16 | andika("a ni tatu")
17 | }
18 | ikiwa 2 {
19 | andika ("a ni mbili")
20 | }
21 | }
22 | ```
23 |
24 | ## Multiple Values in a Case
25 |
26 | Multiple possibilities can be assigned to a single case (ikiwa) statement:
27 |
28 | ```s
29 | badili (a) {
30 | ikiwa 1,2,3 {
31 | andika("a ni kati ya 1, 2 au 3")
32 | }
33 | ikiwa 4 {
34 | andika("a ni 4")
35 | }
36 | }
37 | ```
38 |
39 | ## Default Case (kawaida)
40 |
41 | The default statement will be executed when no condition is satisfied. The default statement is represented by kawaida:
42 |
43 | ```s
44 | fanya z = 20
45 |
46 | badili(z) {
47 | ikiwa 10 {
48 | andika("kumi")
49 | }
50 | ikiwa 30 {
51 | andika("thelathini")
52 | }
53 | kawaida {
54 | andika("ishirini")
55 | }
56 | }
57 | ```
58 |
59 | By understanding switch statements in Nuru, you can create more efficient and organized code that can handle multiple conditions easily.
--------------------------------------------------------------------------------
/repl/docs/en/time.md:
--------------------------------------------------------------------------------
1 | # Time in Nuru
2 |
3 | ## Importing Time
4 |
5 | To use Time in Nuru, you first have to import the `muda` module as follows:
6 |
7 | ```so
8 | tumia muda
9 | ```
10 |
11 | ---
12 |
13 | ## Time Methods
14 |
15 | ### `hasahivi()`
16 |
17 | To get the current time, use `muda.hasahivi()`. It returns a `muda` object with the current time in the format `HH:mm:ss dd-MM-YYYY`.
18 |
19 | ```so
20 | tumia muda
21 |
22 | saivi = muda.hasahivi()
23 | ```
24 |
25 | ---
26 |
27 | ### `leo()`
28 |
29 | To get today’s date in the format `dd-MM-YYYY`:
30 |
31 | ```so
32 | tumia muda
33 |
34 | leo = muda.leo()
35 | ```
36 |
37 | ---
38 |
39 | ### `tangu(time)`
40 |
41 | Gets the total time elapsed **in seconds** from the given time to now. Accepts a `muda` object or string in `HH:mm:ss dd-MM-YYYY` format.
42 |
43 | ```so
44 | tumia muda
45 |
46 | muda_ulioyopita = muda.tangu("15:00:00 01-01-2024")
47 | ```
48 |
49 | ---
50 |
51 | ### `lala(sekunde)`
52 |
53 | Pauses the program for the given number of seconds:
54 |
55 | ```so
56 | tumia muda
57 |
58 | muda.lala(5) // sleeps for 5 seconds
59 | ```
60 |
61 | ---
62 |
63 | ### `baada_ya(sekunde)`
64 |
65 | Returns a `muda` object representing the time after the given number of seconds from now.
66 |
67 | ```so
68 | tumia muda
69 |
70 | baadaye = muda.baada_ya(60) // one minute from now
71 | ```
72 |
73 | ---
74 |
75 | ### `tofauti(muda1, muda2)`
76 |
77 | Returns the difference between two time values in seconds.
78 |
79 | ```so
80 | tumia muda
81 |
82 | saa1 = muda.hasahivi()
83 | saa2 = muda.baada_ya(30)
84 |
85 | tofauti = muda.tofauti(saa2, saa1) // 30
86 | ```
87 |
88 | ---
89 |
90 | ### `ongeza(...)`
91 |
92 | To add time to a `muda` object. You must specify at least one of the following fields `sekunde`, `dakika`, `masaa`, `siku`, `wiki`, `miezi`, `miaka`.
93 |
94 | Example:
95 |
96 | ```so
97 | tumia muda
98 |
99 | sasa = muda.hasahivi()
100 | kesho = sasa.ongeza(siku=1)
101 | mwakani = sasa.ongeza(miaka=1)
102 | ```
103 |
--------------------------------------------------------------------------------
/repl/docs/en/while.md:
--------------------------------------------------------------------------------
1 | # WHILE (WAKATI)
2 |
3 | While loops in Nuru are used to execute a block of code repeatedly, as long as a given condition is true. This page covers the basics of while loops, including how to use the break and continue keywords within them.
4 |
5 | ## Basic Syntax
6 |
7 | A while loop is executed when a specified condition is true. You initiliaze a while loop with the `wakati` keyword followed by the condition in paranthesis `()`. The consequence of the loop should be enclosed in brackets `{}`:
8 | ```s
9 | fanya i = 1
10 |
11 | wakati (i <= 5) {
12 | andika(i)
13 | i++
14 | }
15 | ```
16 | Output
17 | ```s
18 | 1
19 | 2
20 | 3
21 | 4
22 | 5
23 | ```
24 |
25 | ## Break (vunja) and Continue (endelea)
26 | ### Break (Vunja)
27 |
28 | Use the vunja keyword to terminate a loop:
29 |
30 | ```s
31 | fanya i = 1
32 |
33 | wakati (i < 5) {
34 | kama (i == 3) {
35 | andika("nimevunja")
36 | vunja
37 | }
38 | andika(i)
39 | i++
40 | }
41 | ```
42 | Output
43 | ```s
44 | 1
45 | 2
46 | nimevunja
47 | ```
48 |
49 | ### Continue (Endelea)
50 |
51 | Use the endelea keyword to skip a specific iteration:
52 |
53 | ```s
54 | fanya i = 0
55 |
56 | wakati (i < 5) {
57 | i++
58 | kama (i == 3) {
59 | andika("nimeruka")
60 | endelea
61 | }
62 | andika(i)
63 | }
64 | ```
65 | Output
66 | ```s
67 | 1
68 | 2
69 | nimeruka
70 | 4
71 | 5
72 | ```
73 |
74 | By understanding while loops in Nuru, you can create code that repeats a specific action or checks for certain conditions, offering more flexibility and control over your code execution.
--------------------------------------------------------------------------------
/repl/docs/sw/README.md:
--------------------------------------------------------------------------------
1 | # NYARAKA YA LUGHA YA PROGRAMU YA NURU
2 |
3 | Hii nyaraka imeandikwa ikilenga watu wenye uzoefu na kuandika au kupanga programu. Inaelezea sintaksia, aina na namna ya kufanya operesheni mbali mbali kutumia lugha ya NURU.
4 |
5 | ## Yaliyomo
6 |
7 | - [Safu Kwenye Nuru](arrays.md#arrays-in-nuru)
8 | - [Kutengeneza Safu](arrays.md#creating-arrays)
9 | - [Kupata na Kurekebisha vipengele vya Safu](arrays.md#accessing-and-modifying-array-elements)
10 | - [Kuunganisha Safu](arrays.md#concatenating-arrays)
11 | - [Kuangalia uwepo wa vipengele ndani ya safu](arrays.md#checking-for-array-membership)
12 | - [Kupita na Kurejea kwenye safu](arrays.md#looping-over-arrays)
13 | - [Mbinu za Safu](arrays.md#array-methods)
14 | - [idadi()](arrays.md#idadi())
15 | - [sukuma()](arrays.md#sukuma())
16 | - [yamwisho()](arrays.md#yamwisho())
17 | - [Visaidia-kazi vya Nuru](builtins.md#built-in-functions-in-nuru)
18 | - [Kisaidia-kazi andika() ](builtins.md#the-andika()-function)
19 | - [Kisaidia-kazi jaza()](builtins.md#the-jaza()-function)
20 | - [Kisaidia-kazi aina()](builtins.md#the-aina()-function)
21 | - [Kisaidia-kazi fungua()](builtins.md#the-fungua()-function)
22 | - [Maoni kwenye Nuru](comments.md#comments-in-nuru)
23 | - [Maoni ya mstari mmoja](comments.md#single-line-comments)
24 | - [Maoni ya mistari mingi](comments.md#multi-line-comments)
25 | - [Kauli za masharti kwenye Nuru](ifStatements.md#conditional-statements-in-nuru)
26 | - [Kauli ya kama](ifStatements.md#if-statement-(kama))
27 | - [Kauli za Au Kama na Sivyo)](ifStatements.md#else-if-and-else-blocks-(au-kama-and-sivyo))
--------------------------------------------------------------------------------
/repl/docs/sw/arrays.md:
--------------------------------------------------------------------------------
1 | # Orodha Au Safu Katika Nuru
2 |
3 | Safu katika nuru ni miundo ya data ambayo inaweza kubeba vitu vingi, ikiwa ni pamoja na aina za data tofauti tofauti kama `namba`, `tungo`, `buliani`, `vitendakazi`, na thamani `tupu`. Ukurasa huu unaangazia vipengele mbalimbali vya safu, ikiwemo namna ya kutengeneza, kuchambua, na kuzunguka ndani yake kwa kutumia vitendakazi vilivyojengwa ndani ya Nuru.
4 |
5 | ## Kutengeneza Safu
6 |
7 | Kutengeneza safu, tumia mabano mraba na tenganisha kila kitu kimoja kwa kutumia mkwaju:
8 |
9 | ```s
10 | orodha = [1, "pili", kweli]
11 | ```
12 |
13 | ## Kupata na Kubadilisha Vipengele vya Safu
14 |
15 | Safu katika Nuru ni zero-indexed; ikimaanisha kipengele cha kwanza katika safu kina kumbukumbu namba 0. Kupata kipengele, unaweza ukatumia kumbukumbu namba yake ndani ya mabano mraba:
16 |
17 | ```s
18 | namba = [10, 20, 30]
19 | jina = namba[1] // jina is 20
20 | ```
21 |
22 | Unaweza ukabadilisha kipengele katika safu kwa kutumia kumbukumbu namba yake:
23 |
24 | ```s
25 | namba = [10, 20, 30]
26 | namba[1] = 25
27 | andika(namba) // Tokeo: [10,25,30]
28 | ```
29 |
30 | ## Kuunganisha Safu
31 |
32 | Kuunganisha safu mbili au zaidi, tumia kiendeshi `+`:
33 |
34 | ```s
35 | a = [1, 2, 3]
36 | b = [4, 5, 6]
37 | c = a + b
38 | // c is now [1, 2, 3, 4, 5, 6]
39 | ```
40 |
41 | ## Kuangalia Uanachama Katika Safu
42 |
43 | Tumia neno msingi `ktk` kuangalia kama kipengele kipo ndani ya safu:
44 |
45 | ```s
46 | namba = [10, 20, 30]
47 | andika(20 ktk namba) // Tokeo: kweli
48 | ```
49 |
50 | ## Kuzunguka Ndani ya Safu
51 |
52 | Unaweza kutumia maneno msingi `kwa` na `ktk` kuzunguka ndani ya safu. Kuzunguka ndani ya safu na kupata kipengele peke yake tumia sintaksia ifuatayo:
53 |
54 | ```s
55 | namba = [1, 2, 3, 4, 5]
56 |
57 | kwa thamani ktk namba {
58 | andika(thamani)
59 | }
60 |
61 | //Tokeo:
62 | 1
63 | 2
64 | 3
65 | 4
66 | 5
67 | ```
68 |
69 | Kuzunguka ndani ya safu na kupata kumbukumbu namba na kipengele tumia sintaksi aifuatayo:
70 |
71 | ```s
72 | majina = ["Juma", "Asha", "Haruna"]
73 |
74 | kwa idx, jina ktk majina {
75 | andika(idx, "-", jina)
76 | }
77 |
78 | //Tokeo:
79 | 0-Juma
80 | 1-Asha
81 | 2-Haruna
82 | ```
83 |
84 | ## Vitendakazi vya Safu
85 |
86 | Nuru ina vitendakazi mbalimbali vilivyojengwa ndani kwa ajili ya Safu:
87 |
88 | ### idadi()
89 |
90 | `idadi()` hurudisha urefu wa safu:
91 |
92 | ```s
93 | a = [1, 2, 3]
94 | urefu = a.idadi()
95 | andika(urefu) // Tokeo: 3
96 | ```
97 |
98 | ### sukuma()
99 |
100 | `sukuma()` huongeza kipengele kimoja au zaidi mwishoni mwa safu:
101 |
102 | ```s
103 | a = [1, 2, 3]
104 | a.sukuma("s", "g")
105 | andika(a) // Tokeo [1, 2, 3, "s", "g"]
106 | ```
107 |
108 | ### yamwisho()
109 |
110 | `yamwisho()` hurudisha kipengele cha mwisho katika safu, au `tupu` kama safu haina kitu:
111 |
112 | ```s
113 | a = [1, 2, 3]
114 | mwisho = a.yamwisho()
115 | andika(mwisho) // Tokeo: 3
116 |
117 | b = []
118 | mwisho = b.yamwisho()
119 | andika(mwisho) // Tokeo: tupu
120 | ```
121 |
122 | Kwa kutumia taarifa hii, unaweza ukafanyakazi na safu za Nuru kwa ufanisi, kufanya iwe rahisi kuchambua mikusanyo ya data katika programu zako.
123 |
--------------------------------------------------------------------------------
/repl/docs/sw/bools.md:
--------------------------------------------------------------------------------
1 | # Kufanya Kazi na Buliani Katika Nuru
2 |
3 | Vitu vyote katika Nuru ni kweli, yaani thamani yoyote ni kweli isipokua tupu and sikweli. Hutumika kutathmini semi ambazo zinarudisha kweli au sikweli.
4 |
5 | ## Kutathmini Semi za Buliani
6 |
7 | ### Kutathmini Semi Rahisi
8 |
9 | Katika Nuru, unaweza kutathmini semi rahisi zinazorudisha thamani ya buliani:
10 |
11 | ```go
12 | andika(1 > 2) // Matokeo: `sikweli`
13 |
14 | andika(1 + 3 < 10) // Matokeo: `kweli`
15 | ```
16 |
17 | ### Kutathmini Semi Tata
18 |
19 | Katika Nuru, unaweza kutumia viendeshaji vya buliani kutathmini semi tata:
20 |
21 | ```go
22 | a = 5
23 | b = 10
24 | c = 15
25 |
26 | tokeo = (a < b) && (b < c)
27 |
28 | kama (tokeo) {
29 | andika("Hali zote mbili ni kweli")
30 | } sivyo {
31 | andika("Angalau hali moja ni sikweli")
32 | }
33 | // Tokeo: "Hali zote mbili ni kweli"
34 | ```
35 |
36 | Hapa tumetengeneza vibadilika vitatu a,b,c. Kisha tukatathmini semi (a < b) && (b < c). Kwa sababu semi zote mbili ni kweli, tokeo litakua "Hali zote mbili ni kweli".
37 |
38 | ## Vitendakazi vya Buliani
39 |
40 | Nuru ina vitendakazi vya buliani kadhaa ambavyo unaweza ukatumia kutathmini semi:
41 |
42 | ### Kitendakazi `&&`
43 |
44 | Kitendakazi `&&` hutathmini kwenda kweli kama tu vitu vyote vinavyohusika ni kweli. Kwa mfano:
45 |
46 | ```go
47 | andika(kweli && kweli) // Tokeo: `kweli`
48 |
49 | andika(kweli && sikweli) // Tokeo: `sikweli`
50 | ```
51 |
52 | ### Kitendakazi `||`
53 |
54 | Kitendakazi || hutathmini kwenda kweli kama angalau kitu kimoja kati ya vyote vinavyohusika ni kweli. Kwa mfano:
55 |
56 | ```go
57 | andika(kweli || sikweli) // Tokeo: `kweli`
58 |
59 | andika(sikweli || sikweli) // Tokeo: `sikweli`
60 | ```
61 |
62 | ### Kitendakazi `!`
63 |
64 | Kitendakazi `!` hukanusha thamani ya kitu. Kwa mfano:
65 |
66 | ```go
67 | andika(!kweli) // Tokeo: `sikweli`
68 |
69 | andika(!sikweli) // Tokeo: `kweli`
70 | ```
71 |
72 | ## Kufanya Kazi na Thamani za Buliani Katika Vitanzi
73 |
74 | Katika Nuru, unaweza ukatumia semi za buliani katika vitanzi kuendesha tabia zake. Kwa mfano:
75 |
76 | ```go
77 | namba = [1, 2, 3, 4, 5]
78 |
79 | kwa thamani ktk namba {
80 | kama (thamani % 2 == 0) {
81 | andika(thamani, " ni namba shufwa")
82 | } sivyo {
83 | andika(thamani, " ni namba witiri")
84 | }
85 | }
86 |
87 | // Output:
88 | // 1 ni namba witiri
89 | // 2 ni namba shufwa
90 | // 3 ni namba witiri
91 | // 4 ni namba shufwa
92 | // 5 ni namba witiri
93 | ```
94 |
95 | Hapa , tumetengeneza safu yenye namba 1 hadi 5 kisha tukazunguka ndani ya safu hiyo na kwa kila namba tukatumia kitendakazi `%` ilikubaini kama namba ni shufwa au witiri. Matokeo yatakua ni "ni namba shufwa" kwa namba shufwa na "ni namba witiri" kwa namba witiri.
96 |
97 | Vitu buliani katika Nuru vinaweza kutumika kutathmini semi ambazo zinarudisha thamani ya kweli au sikweli. Unaweza kutumia vitendakazi vya buliani kutathmini semi tata na kuendesha tabia ya vitanzi. Kuelewa namna ya kufanya kazi na thamani za buliani ni ujuzi wamsingi kwa mtengenezaji programu yeyote wa Nuru.
98 |
--------------------------------------------------------------------------------
/repl/docs/sw/builtins.md:
--------------------------------------------------------------------------------
1 | # Vitendakazi Vilivyojengwa Ndani ya Nuru
2 |
3 | Nuru ina vitendakazi kadhaa vilivyojengwa ndani vinavyofanya kazi husika.
4 |
5 | ## Kitendakazi andika()
6 |
7 | Kitendakazi `andika()` kinatumika kuchapisha ujumbe kwenye konsoli. Inawezakuchukua hoja sifuri au zaidi, na hoja zitachapishwa na nafasi kati yao. Kwa kuongeza, `andika()` huhimili uundaji wa msingi kama vile `/n` kwa ajili ya mstari mpya, `/t` kwa ajili ya nafasi ya kichupo, na `\\` kwa ajili ya mkwajunyuma. Mfano:
8 |
9 | ```go
10 | andika(1, 2, 3) // Output: 1 2 3
11 | ```
12 |
13 | ```go
14 | andika("Jina: Asha /n Umri: 20 /n Chuo: IFM")
15 |
16 | // Output:
17 | // Jina: Asha
18 | // Umri: 20
19 | // Chuo: IFM
20 | ```
21 |
22 | ## Kitendakazi jaza()
23 |
24 | Kitendakazi `jaza()` kinatumika kupata ingizo kutoka kwa mtumiaji. Inawezakuchukua hoja sifuri au moja, ambayo ni utungo utakao tumika kama kimahasishi kwa mtumiaji. Mfano:
25 |
26 | ```go
27 | fanya salamu = unda() {
28 | fanya jina = jaza("Unaitwa nani? ")
29 | andika("Mambo vipi", jina)
30 | }
31 |
32 | salamu()
33 | ```
34 |
35 | Katika mfano huu, tunaainisha kitendakazi `salamu()` ambacho kinamhamasisha mtumiaji kuingiza jina kwa kutumia kitendakazi `jaza()`. Kisha tunatumia kitendakazi `andika()` kuchapisha ujumbe unaobeba jina la mtumiaji aliloingiza.
36 |
37 | ## Kitendakazi aina()
38 |
39 | Kitendakazi `aina()` kinatumika kutambua aina ya kitu. Inakubali hoja moja, na thamani inayorudi hua ni utungo unaoonyesha aina ya kitu. Mfano:
40 |
41 | ```go
42 | aina(2) // Output: "NAMBA"
43 | aina("Nuru") // Output: "NENO"
44 | ```
45 |
46 | ## Kitendakazi fungua()
47 |
48 | Kitendakazi `fungua()` kinatumika kufungua faili. Inakubali hoja moja, ambayo ni njia ya faili unalotaka kufungua. Mfano:
49 |
50 | ```go
51 | faili = fungua("data.txt")
52 | ```
53 |
54 | Katika mfano huu, tumetumia kitendakazi `fungua()` kufungua faili linaloitwa "data.txt". Kibadilika `faili` kinabeba kumbukumbu ya faili lililofunguliwa.
55 |
--------------------------------------------------------------------------------
/repl/docs/sw/dictionaries.md:
--------------------------------------------------------------------------------
1 | # Kamusi Katika Nuru
2 |
3 | Kamusi katika Nuru ni miundo ya data inayotunza jozi za funguo-thamani. Ukurasa huu unatoa maelezo kuhusu Kamusi katika Nuru, ikiwemo namna ya kutengeneza, namna ya kubadilisha, na namna ya kuzunguka ndani yake.
4 |
5 | ## Kutengeneza Kamusi
6 |
7 | Kamusi zinawekwa kwenye mabano singasinga na hujumuisha funguo na thamani zake zikitenganishwa na nukta pacha. Mfano wa uainishwaji wa kamusi:
8 |
9 | ```go
10 |
11 | orodha = {"jina": "Juma", "umri": 25}
12 | ```
13 |
14 | Funguo zinawezakua tungo, namba, desimali, au buliani na thamani inaweza kua aina ya data yoyote ikiwemo tungo, namba, desimali, buliani, tupu, au kitendakazi:
15 |
16 | ```go
17 | k = {
18 | "jina": "Juma",
19 | "umri": 25,
20 | kweli: "kweli",
21 | "salimu": unda(x) { andika("habari", x) },
22 | "sina thamani": tupu
23 | }
24 | ```
25 |
26 | ## Kupata Vipengele
27 |
28 | Unaweza kupata vipengele vya kamusi kwa kutumia funguo zake:
29 |
30 | ```go
31 | k = {
32 | "jina": "Juma",
33 | "umri": 25,
34 | kweli: "kweli",
35 | "salimu": unda(x) { andika("habari", x) },
36 | "sina thamani": tupu
37 | }
38 |
39 | andika(k[kweli]) // kweli
40 | andika(k["salimu"]("Juma")) // habari Juma
41 | ```
42 |
43 | ## Kuboresha Vipengele
44 |
45 | Boresha thamani ya kipengele kwa kukipa thamani mpya kwenye funguo yake:
46 |
47 | ```go
48 | k = {
49 | "jina": "Juma",
50 | "umri": 25,
51 | kweli: "kweli",
52 | "salimu": unda(x) { andika("habari", x) },
53 | "sina thamani": tupu
54 | }
55 |
56 | k['umri'] = 30
57 | andika(k['umri']) // 30
58 | ```
59 |
60 | ## Kuongeza Vipengele Vipya
61 |
62 | Ongeza jozi mpya ya funguo-thamani kwenye kamusi kwa kuipa thamani funguo ambayo haipo kwenye kamusi husika:
63 |
64 | ```go
65 | k["lugha"] = "Kiswahili"
66 | andika(k["lugha"]) // Kiswahili
67 | ```
68 |
69 | ## Kuunganisha Kamusi
70 |
71 | Unganisha kamusi mbili kwa kutumia kiendeshi `+`:
72 |
73 | ```go
74 | matunda = {"a": "apple", "b": "banana"}
75 | mboga = {"c": "tembele", "d": "mchicha"}
76 | vyakula = matunda + mboga
77 | andika(vyakula) // {"a": "apple", "b": "banana", "c": "tembele", "d": "mchicha"}
78 | ```
79 |
80 | ## Angalia Kama Funguo Ipo Kwenye Kamusi
81 |
82 | Tumia neno msingi `ktk` kuangalia kama funguo ipo kwenye kamusi:
83 |
84 | ```go
85 |
86 | k = {
87 | "jina": "Juma",
88 | "umri": 25,
89 | kweli: "kweli",
90 | "salimu": unda(x) { andika("habari", x) },
91 | "sina thamani": tupu
92 | }
93 |
94 | "umri" ktk k // kweli
95 | "urefu" ktk k // sikweli
96 | ```
97 |
98 | ## Kuzunguka Ndani Ya Kamusi
99 |
100 | Zunguka ndani ya kamusi kupata funguo na thamani zake:
101 |
102 | ```go
103 |
104 | hobby = {"a": "kulala", "b": "kucheza mpira", "c": "kuimba"}
105 |
106 | kwa i, v ktk hobby {
107 | andika(i, "=>", v)
108 | }
109 |
110 | //Output
111 |
112 | a => kulala
113 | b => kucheza mpira
114 | c => kuimba
115 | ```
116 |
117 | Kuzunguka ndani ya kamusi na kupata thamani peke yake:
118 |
119 | ```go
120 |
121 | hobby = {"a": "kulala", "b": "kucheza mpira", "c": "kuimba"}
122 |
123 | kwa i, v ktk hobby {
124 | andika(i, "=>", v)
125 | }
126 |
127 | //Output
128 |
129 | kulala
130 | kucheza mpira
131 | kuimba
132 | ```
133 |
134 | Kwa ufahamu huu, unaweza ukatumia kamusi kikamilifu katika Nuru kutunza na kusimamia jozi za funguo-thamani, na kupata namna nyumbufu ya kupangilia na kupata data katika programu zako.
135 |
--------------------------------------------------------------------------------
/repl/docs/sw/for.md:
--------------------------------------------------------------------------------
1 | # Vitanzi Vya Kwa Katika Nuru
2 |
3 | Vitanzi vya `kwa` ni muundo msingi wa udhibiti katika Nuru ambavyo hutumika kuzunguka vitu vinavyozungukika kama tungo, safu, na kamusi. Ukurasahuu unaangazia sintaksia na matumizi ya Vitanzi katika Nuru, ikiwemo kuzunguka ndani ya jozi ya funguo-thamani, na matumizi ya matamshi `vunja` na `endelea`.
4 |
5 | ## Sintaksia
6 |
7 | Kutengeneza kitanzi cha `kwa`, tumia neno msingi `kwa` likifwatiwa na kitambulishi cha muda mfupi kama vile `i` au `v` na kitu kinachozungukika. Funga mwili wa kitanzi na mabano singasinga `{}`. Mfano unaotumia tungo:
8 |
9 | ```go
10 | jina = "lugano"
11 |
12 | kwa i ktk jina {
13 | andika(i)
14 | }
15 |
16 | // Tokeo:
17 | l
18 | u
19 | g
20 | a
21 | n
22 | o
23 | ```
24 |
25 | ## Kuzunguka Ndani ya Jozi ya Funguo-Thamani
26 |
27 | ### Kamusi
28 |
29 | Nuru inakuruhusu kuzunguka ndani ya kamusi kupata thamani moja moja au jozi ya funguo na thamani yake. Kupata tu thamani, tumia kitambulisha cha muda mfupi:
30 |
31 | ```go
32 | kamusi = {"a": "andaa", "b": "baba"}
33 |
34 | kwa v ktk kamusi {
35 | andika(v)
36 | }
37 |
38 | // Tokeo:
39 |
40 | andaa
41 | baba
42 | ```
43 |
44 | Kupata thamani ya funguo na thamani zake, tumia vitambulishi vya muda mfupi viwili:
45 |
46 | ```go
47 |
48 | kwa k, v ktk kamusi {
49 | andika(k + " ni " + v)
50 | }
51 |
52 | // Tokeo:
53 |
54 | a ni andaa
55 | b ni baba
56 | ```
57 |
58 | ### Tungo
59 |
60 | Kuzunguka juu ya thamani za tungo, tumia kitambulishi cha muda mfupi:
61 |
62 | ```go
63 | kwa v ktk "mojo" {
64 | andika(v)
65 | }
66 |
67 | // Tokeo:
68 |
69 | m
70 | o
71 | j
72 | o
73 | ```
74 |
75 | Kuzunguka juu ya funguo na thamani zake, tumia vitambulishi vya muda mfupi viwili:
76 |
77 | ```go
78 | kwa i, v ktk "mojo" {
79 | andika(i, "->", v)
80 | }
81 |
82 | // Tokeo:
83 |
84 | 0 -> m
85 | 1 -> o
86 | 2 -> j
87 | 3 -> o
88 | ```
89 |
90 | ### Safu
91 |
92 | Kuzunguka juu ya thamani za safu, tumia kitambulishi cha muda mfupi:
93 |
94 | ```go
95 | majina = ["juma", "asha", "haruna"]
96 |
97 | kwa v ktk majina {
98 | andika(v)
99 | }
100 |
101 | // Tokeo:
102 |
103 | juma
104 | asha
105 | haruna
106 | ```
107 |
108 | Kuzunguka juu ya funguo na thamani katika safy, tumia vitambulishi vya muda mfupi viwili:
109 |
110 | ```go
111 | kwa i, v ktk majina {
112 | andika(i, "-", v)
113 | }
114 |
115 | // Tokeo:
116 |
117 | 0 - juma
118 | 1 - asha
119 | 2 - haruna
120 | ```
121 |
122 | ## Vunja na Endelea
123 |
124 | ### Vunja
125 |
126 | Tumia neno msingi `vunja` kisitisha kitanzi:
127 |
128 | ```go
129 |
130 | kwa i, v ktk "mojo" {
131 | kama (i == 2) {
132 | andika("nimevunja")
133 | vunja
134 | }
135 | andika(v)
136 | }
137 |
138 | // Tokeo:
139 |
140 | m
141 | o
142 | j
143 | nimevunja
144 |
145 | ```
146 |
147 | ### Endelea
148 |
149 | Tumia neno msingi `endelea` kuruka mzunguko maalum:
150 |
151 | ```go
152 | kwa i, v ktk "mojo" {
153 | kama (i == 2) {
154 | andika("nimeruka")
155 | endelea
156 | }
157 | andika(v)
158 | }
159 |
160 | // Tokeo:
161 |
162 | m
163 | o
164 | nimeruka
165 | o
166 | ```
167 |
--------------------------------------------------------------------------------
/repl/docs/sw/functions.md:
--------------------------------------------------------------------------------
1 | # Undo (Functions)
2 |
3 | Vitendakazi ni sehemu ya msingi ya Nuru inayokuwezesha kuainisha mapande ya msimbo yanayoweza kutumika tena. Ukurasa huu unaainisha sintaksia na matumizi ya vitendakazi katika nuru ikiwemo vipengele, vipengele vya msingi, matamshi ya kurudisha, kujirudia, na vifungizi.
4 |
5 | ## Sintaksia
6 |
7 | Pande la kitendakazi huanza na neno msingi `unda` likifuatiwa na vipengele vinavyowekwa ndani ya mabano `()` na mwili unaowekwa ndani ya mabano singasinga `{}`. Vitendakazi lazima viwekwe kwenye kibadiliki:
8 |
9 | ```go
10 | jumla = unda(x, y) {
11 | rudisha x + y
12 | }
13 |
14 | jumla(2, 3) // 5
15 | ```
16 |
17 | ## Vipengele
18 |
19 | Vitendakazi vinawezakuwa nazifuri au idadi yoyote ya vipengele. Vipengele vinawezakua vya aina yoyote hata vitendakazi vingine:
20 |
21 | ```go
22 | salamu = unda(jina) {
23 | andika("Habari yako", jina)
24 | }
25 |
26 | salamu("asha") // Habari yako asha
27 | ```
28 |
29 | ## Vipengele Vya Msingi
30 |
31 | Vitendakazi vinawezakupewa vipengele vya msingi:
32 |
33 | ```go
34 | salimu = unda(salamu="Habari") {
35 | andika(salamu)
36 | }
37 |
38 | salimu() // Habari
39 | salimu("Mambo") // Mambo
40 | ```
41 |
42 | ## Rudisha
43 |
44 | Unaweza pia ukarudisha thamani kwa kutumia neno msingi `rudisha`. Neno msingi `rudisha` husitisha pande la msimbo na kurudisha thamani:
45 |
46 | ```go
47 | mfano = unda(x) {
48 | rudisha "nimerudi"
49 | andika(x)
50 | }
51 |
52 | mfano("x") // nimerudi
53 | ```
54 |
55 | ## Kujirudia
56 |
57 | Nuru pia inahimili kujirudia. Mfano wa kujirudia kwa kitendakazi cha Fibonacci:
58 |
59 | ```go
60 |
61 | fib = unda(n) {
62 | kama (n <= 1) {
63 | rudisha n
64 | } sivyo {
65 | rudisha fib(n-1) + fib(n-2)
66 | }
67 | }
68 |
69 | andika(fib(10)) // 55
70 | ```
71 |
72 | Kitendakazi fib kinakokotoa namba ya Fibonacci ya n kwa kujiita yenyewe ikiwa na n-1 na n-2 kama vipengele mpaka ambapo n ni ndogo kuliko au sawa na moja.
73 |
74 | ## Vifungizi
75 |
76 | Vifungizi ni vitendakazi visivyo na jina ambayo vinaweza kudaka na kuhifadhi marejeo ya vibadilika kutoka katika muktadha unaovizunguka. Katika Nuru, unaweza kutengeneza vifungizi kwa kutumia neno msingin `unda` bila kuiweka kwenye kibadiliki. Mfano:
77 |
78 | ```go
79 | fanya jum = unda(x) {
80 | rudisha unda(y) {
81 | rudisha x + y
82 | }
83 | }
84 |
85 | fanya jum_x = jum(5)
86 | andika(jum_x(3)) // 8
87 | ```
88 |
89 | Katika mfano hapo juu, kitendakazi `jum` kinarudisha kitendakazi kingine ambacho kinabeba kipengele kimoja tu `y`. Kitendakazi kinachorudisha kinawezakupata kibadiliki x kutoka katika muktadha unaokizunguka.
90 |
91 | Sasa umeshaelewa misingi ya vitendakazi katika Nuru, ikiwemo kujirudia na vifungizi, unaweza ukatengeneza mapande ya msimbo yanayoweza kutumika tena na tena na kurahisisha programu zako na kuboresha mpangilio wa msimbo wako.
92 |
--------------------------------------------------------------------------------
/repl/docs/sw/identifiers.md:
--------------------------------------------------------------------------------
1 | # Vitambulisho katika Nuru
2 |
3 | Vitambulisho hutumika kuweka majina kwenye vigezo, vitendakazi na vipengele vingine katika msimbo wako wa Nuru. Ukurasa huu unashughulikia sheria na mbinu bora za kuunda vitambulisho katika Nuru.
4 |
5 | ## Sheria za Sintaksia
6 |
7 | Vitambulisho vinaweza kuwa na herufi, nambari na nistari wa chini `_`. Walakini, kuna sheria chache ambazo unapaswa kufuata wakati wa kuunda vitambulisho:
8 |
9 | - Vitambulisho haviwezi kuanza na nambari.
10 | - Vitambulisho huwa na tofauti kulingana na matumizi ya herufi kubwa na ndogo. Kwa mfano, `kibadilikaChangu` na `kibadilikachangu` huchukuliwa kuwa vitambulisho tofauti.
11 |
12 | Hapa kuna mifano ya vitambulisho halali:
13 |
14 | ```go
15 | fanya mwaka_wa_kuzaliwa = 2020
16 | andika(mwaka_wa_kuzaliwa) // 2020
17 |
18 | fanya badili_c_kwenda_p = "C kwenda P"
19 | andika(badili_c_kwenda_p) // "C kwenda P"
20 | ```
21 |
22 | Katika mifano iliyo hapo juu, mwaka_wa_kuzaliwa na badili_c_kwenda_p zote ni vitambulisho halali.
23 |
24 | ## Mazoea Bora
25 |
26 | Wakati wa kuchagua vitambulisho, ni muhimu kufuata mazoea bora ili kuhakikisha kuwa msimbo wako uko wazi na rahisi kueleweka:
27 |
28 | - Tumia majina yanayoelezea wazi kusudi au maana ya kigezo au kitendakazi.
29 | - Fuata kanuni thabiti ya kuweka majina, kama vile camelCase (kibadilikaChangu) au snake_case (kibadilika_changu).
30 | - Epuka kutumia majina tofauti ya herufi moja, isipokuwa kwa vijisehemu vinavyokubalika kwa kawaida kama vile vihesabu vitanzi (i, j, k).
31 |
32 | Kwa kufuata mbinu bora hizi unapounda vitambulisho, utafanya code yako ya Nuru iwe rahisi kusoma na kutunza kwa wewe na wengine.
33 |
--------------------------------------------------------------------------------
/repl/docs/sw/if.md:
--------------------------------------------------------------------------------
1 | # Kama/Sivyo (If/Else)
--------------------------------------------------------------------------------
/repl/docs/sw/keywords.md:
--------------------------------------------------------------------------------
1 | # Maneno Muhimu (Keywords)
--------------------------------------------------------------------------------
/repl/docs/sw/maoni.md:
--------------------------------------------------------------------------------
1 | # Maoni Katika Nuru
2 |
3 | Katika Nuru, unaweza kuandika maoni kutoa maelezo na hati kwa kazi yako. Maoni ni mistari ya maandishi ambayo hupuuzwa na mfasiri (interpreter) wa Nuru, kwa hivyo haitaathiri tabia ya programu yako. Kuna aina mbili za maoni katika Nuru: maoni ya mstari mmoja na maoni ya mistari mingi.
4 |
5 | ## Maoni ya Mstari Mmoja
6 |
7 | Maoni ya mstari mmoja yanatumiwa kutoa maelezo mafupi au hati kwa mstari mmoja wa kazi. Kuandika maoni ya mstari mmoja katika Nuru, tumia mikwaju miwili ya mbele (//) ikifuatiwa na maandishi ya maoni yako. Hapa kuna mfano:
8 |
9 | ```s
10 | // Mstari huu utapuuzwa na mfasiri wa Nuru
11 | ```
12 |
13 | Katika mfano huu, maandishi ya maoni "Mstari huu utapuuzwa na mfasiri wa Nuru" yatapuuzwa na mfasiri, kwa hivyo haitaathiri tabia ya programu.
14 |
15 | ## Maoni ya Mistari Mingi
16 |
17 | Maoni ya mistari mingi yanatumiwa kutoa maelezo ya kina zaidi au hati kwa mistari mingi ya programu yako. Kuandika maoni ya mistari mingi katika Nuru, tumia ukwaju wa mbele ikifuatiwa na nyota ( /* ) kuanza maoni, na nyota ikifuatiwa na ukwaju wa mbele ( */ ) kumaliza maoni. Hapa kuna mfano:
18 |
19 | ```s
20 | /
21 | Mistari hii
22 | Ita
23 | puuzwa
24 | /
25 | ```
26 |
27 | Katika mfano huu, mistari yote kati ya alama /* na */ itapuuzwa na mfasiri wa Nuru, kwa hivyo haitaathiri tabia ya programu.
28 |
29 | Kwa kutumia maoni ya mstari mmoja na maoni ya mistari mingi katika Nuru, unaweza kufanya kazi yako iwe rahisi kusoma na kudumisha kwa ajili yako na wengine ambao watahitaji kufanya kazi na programu yako katika siku zijazo.
30 |
--------------------------------------------------------------------------------
/repl/docs/sw/null.md:
--------------------------------------------------------------------------------
1 | # Tupu (Null)
--------------------------------------------------------------------------------
/repl/docs/sw/numbers.md:
--------------------------------------------------------------------------------
1 | # Namba na Desimali (Ints/Floats)
--------------------------------------------------------------------------------
/repl/docs/sw/operators.md:
--------------------------------------------------------------------------------
1 | # Matendaji (Operators)
--------------------------------------------------------------------------------
/repl/docs/sw/range.md:
--------------------------------------------------------------------------------
1 | ## Kitendakazi cha Mfululizo
2 |
3 | Kitendakazi cha `mfululizo` hutoa mfululizo wa nambari, sawa na kitendakazi cha `range()` cha Python. Kinaweza kutumika katika vitanzi au kuunda safu za nambari zinazofuatana.
4 |
5 | ### Muundo
6 |
7 | ```go
8 | mfululizo(mwisho)
9 | mfululizo(mwanzo, mwisho)
10 | mfululizo(mwanzo, mwisho, hatua)
11 | ```
12 |
13 | ### Vipengele
14 |
15 | - `mwisho`: Kikomo cha juu cha mfululizo (haijumuishwi).
16 | - `mwanzo` (si lazima): Thamani ya kuanzia ya mfululizo. Chaguo-msingi ni 0.
17 | - `hatua` (si lazima): Ongezeko kati ya kila nambari katika mfululizo. Chaguo-msingi ni 1.
18 |
19 | ### Thamani Inayorudishwa
20 |
21 | Hurudisha safu ya nambari kamili.
22 |
23 | ### Mifano
24 |
25 | ```go
26 | // Toa nambari kutoka 0 hadi 4
27 | kwa i katika mfululizo(5) {
28 | andika(i)
29 | }
30 | // Tokeo: 0 1 2 3 4
31 |
32 | // Toa nambari kutoka 1 hadi 9
33 | kwa i katika mfululizo(1, 10) {
34 | andika(i)
35 | }
36 | // Tokeo: 1 2 3 4 5 6 7 8 9
37 |
38 | // Toa nambari shufwa kutoka 0 hadi 8
39 | kwa i katika mfululizo(0, 10, 2) {
40 | andika(i)
41 | }
42 | // Tokeo: 0 2 4 6 8
43 |
44 | // Toa nambari kwa mpangilio wa kurudi nyuma
45 | kwa i katika mfululizo(10, 0, -1) {
46 | andika(i)
47 | }
48 | // Tokeo: 10 9 8 7 6 5 4 3 2 1
49 | ```
50 |
51 | ### Vidokezo
52 |
53 | - Thamani ya `mwisho` haijumuishwi, ikimaanisha mfululizo utasimama kabla ya kufikia thamani hii.
54 | - Ikiwa `hatua` hasi imetolewa, `mwanzo` inapaswa kuwa kubwa kuliko `mwisho`.
55 | - Thamani ya `hatua` haiwezi kuwa sifuri.
56 |
--------------------------------------------------------------------------------
/repl/docs/sw/strings.md:
--------------------------------------------------------------------------------
1 | # Neno (Strings)
--------------------------------------------------------------------------------
/repl/docs/sw/switch.md:
--------------------------------------------------------------------------------
1 | # Badili (Switch)
--------------------------------------------------------------------------------
/repl/docs/sw/while.md:
--------------------------------------------------------------------------------
1 | # Wakati (While)
--------------------------------------------------------------------------------
/styles/styles.go:
--------------------------------------------------------------------------------
1 | package styles
2 |
3 | import "github.com/charmbracelet/lipgloss"
4 |
5 | var (
6 | TitleStyle = lipgloss.NewStyle().Margin(1, 0).Foreground(lipgloss.Color("#aa6f5a"))
7 | VersionStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("#ff9671"))
8 | AuthorStyle = lipgloss.NewStyle().Italic(true).Foreground(lipgloss.Color("#ff9671"))
9 | HelpStyle = lipgloss.NewStyle().Italic(true).Faint(true).Foreground(lipgloss.Color("#ffe6d6"))
10 | ErrorStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("196")).Italic(true)
11 | ReplStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("76")).Italic(true)
12 | PromptStyle = ""
13 | )
14 |
--------------------------------------------------------------------------------
/third_party/math/test.nr:
--------------------------------------------------------------------------------
1 | tumia "hesabu"
2 |
3 | andika("abs: ",hesabu.abs(-42));
4 | andika("acos: ",hesabu.acos(0.5));
5 | andika("acosh: ",hesabu.acosh(2));
6 | andika("asin: ", hesabu.asin(0.5));
7 | andika("asinh: ",hesabu.asinh(2));
8 | andika("atan: ",hesabu.atan(1));
9 | andika("atan2: ",hesabu.atan2(1, 1));
10 | andika("atanh: ",hesabu.atanh(0.5));
11 | andika("cbrt: ",hesabu.cbrt(8));
12 | andika("root: ",hesabu.root(27, 3));
13 | andika("ceil: ",hesabu.ceil(4.3));
14 | andika("cos: ",hesabu.cos(5));
15 | andika("cosh: ",hesabu.cosh(5));
16 | andika("exp: ",hesabu.exp(2));
17 | andika("expm1: ",hesabu.expm1(1));
18 | andika("floor: ",hesabu.floor(4.7));
19 | andika("hypot: ",hesabu.hypot([3, 4]));
20 | andika("log: ",hesabu.log(2));
21 | andika("log10: ",hesabu.log10(100));
22 | andika("log1p: ",hesabu.log1p(1));
23 | andika("log2: ",hesabu.log2(8));
24 | andika("max: ",hesabu.max([4, 2, 9, 5]));
25 | andika("min: ",hesabu.min([4, 2, 9, 5]));
26 | andika("round: ",hesabu.round(4.6, "rpi"));
27 | andika("sign: ",hesabu.sign(-5));
28 | andika("sin: ",hesabu.sin(1));
29 | andika("sinh: ",hesabu.sinh(0));
30 | andika("sqrt: ",hesabu.sqrt(4));
31 | andika("tan: ",hesabu.tan(1));
32 | andika("tanh: ",hesabu.tanh(0));
33 | andika("factorial: ",hesabu.factorial(5));
34 | andika("isNegative: ",hesabu.isNegative(-5));
35 | andika("isInteger: ",hesabu.isInteger(4.5));
36 | andika("getIntegerPart: ",hesabu.getIntegerPart(4.5));
37 | andika("list: ",hesabu.list(1, 5, 1));
38 | fanya callback = unda(accumulator, currentValue){
39 | rudisha accumulator + currentValue;
40 | }
41 | andika("reduce: ",hesabu.reduce([1, 2, 3, 4],callback,0) );
42 |
--------------------------------------------------------------------------------
/token/token.go:
--------------------------------------------------------------------------------
1 | // This is where we define our tokens
2 |
3 | package token
4 |
5 | type TokenType string
6 |
7 | type Token struct {
8 | Type TokenType
9 | Literal string
10 | Line int
11 | }
12 |
13 | const (
14 | ILLEGAL = "HARAMU"
15 | EOF = "MWISHO"
16 |
17 | // Identifiers + literals
18 | IDENT = "KITAMBULISHI"
19 | INT = "NAMBA"
20 | STRING = "NENO"
21 | FLOAT = "DESIMALI"
22 |
23 | // Operators
24 | ASSIGN = "="
25 | PLUS = "+"
26 | MINUS = "-"
27 | BANG = "!"
28 | ASTERISK = "*"
29 | POW = "**"
30 | SLASH = "/"
31 | MODULUS = "%"
32 | LT = "<"
33 | LTE = "<="
34 | GT = ">"
35 | GTE = ">="
36 | EQ = "=="
37 | NOT_EQ = "!="
38 | AND = "&&"
39 | OR = "||"
40 | PLUS_ASSIGN = "+="
41 | PLUS_PLUS = "++"
42 | MINUS_ASSIGN = "-="
43 | MINUS_MINUS = "--"
44 | ASTERISK_ASSIGN = "*="
45 | SLASH_ASSIGN = "/="
46 | MODULUS_ASSIGN = "%="
47 | SHEBANG = "#!"
48 |
49 | //Delimiters
50 | COMMA = ","
51 | SEMICOLON = ";"
52 | LPAREN = "("
53 | RPAREN = ")"
54 | LBRACE = "{"
55 | RBRACE = "}"
56 | LBRACKET = "["
57 | RBRACKET = "]"
58 | COLON = ":"
59 | DOT = "."
60 | AT = "@"
61 |
62 | // Keywords
63 | FUNCTION = "FUNCTION"
64 | LET = "FANYA"
65 | TRUE = "KWELI"
66 | FALSE = "SIKWELI"
67 | IF = "KAMA"
68 | ELSE = "SIVYO"
69 | RETURN = "RUDISHA"
70 | WHILE = "WAKATI"
71 | NULL = "TUPU"
72 | BREAK = "VUNJA"
73 | CONTINUE = "ENDELEA"
74 | IN = "KTK"
75 | FOR = "KWA"
76 | SWITCH = "BADILI"
77 | CASE = "IKIWA"
78 | DEFAULT = "KAWAIDA"
79 | IMPORT = "TUMIA"
80 | PACKAGE = "PAKEJI"
81 | )
82 |
83 | var keywords = map[string]TokenType{
84 | "unda": FUNCTION,
85 | "fanya": LET,
86 | "kweli": TRUE,
87 | "sikweli": FALSE,
88 | "kama": IF,
89 | "au": ELSE,
90 | "sivyo": ELSE,
91 | "wakati": WHILE,
92 | "rudisha": RETURN,
93 | "vunja": BREAK,
94 | "endelea": CONTINUE,
95 | "tupu": NULL,
96 | "ktk": IN,
97 | "kwa": FOR,
98 | "badili": SWITCH,
99 | "ikiwa": CASE,
100 | "kawaida": DEFAULT,
101 | "tumia": IMPORT,
102 | "pakeji": PACKAGE,
103 | "@": AT,
104 | }
105 |
106 | func LookupIdent(ident string) TokenType {
107 | if tok, ok := keywords[ident]; ok {
108 | return tok
109 | }
110 | return IDENT
111 | }
112 |
--------------------------------------------------------------------------------
/upx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NuruProgramming/Nuru/0805bb2df91dda4040be58160f8db114cc84764f/upx
--------------------------------------------------------------------------------