├── src ├── object_errors.zig ├── emfiles │ └── about.txt ├── pankti.zig ├── vm_errors.zig ├── openfile.zig ├── flags.zig ├── stdlib │ ├── os_errors.zig │ ├── string_errors.zig │ ├── map.zig │ ├── os.zig │ ├── stdlib.zig │ ├── string.zig │ ├── file.zig │ ├── big.zig │ └── math.zig ├── bengali │ ├── names.zig │ └── bn.zig ├── writer.zig ├── khataapi.zig ├── ansicolors.zig ├── wasm.zig ├── value_errors.zig ├── table.zig ├── builtins.zig ├── main.zig ├── lexer │ └── keywords.zig ├── stack.zig ├── compiler_errors.zig ├── run.zig ├── utils.zig ├── instruction.zig └── value.zig ├── tests ├── __init__.py ├── samples │ ├── stdlib_math_deg.pank │ ├── stdlib_math_floor.pank │ ├── stdlib_math_gcd.pank │ ├── stdlib_math_lcm.pank │ ├── stdlib_math_log.pank │ ├── stdlib_math_log10.pank │ ├── stdlib_math_logx.pank │ ├── stdlib_math_num.pank │ ├── stdlib_math_rad.pank │ ├── stdlib_math_round.pank │ ├── stdlib_math_sqrt.pank │ ├── print_1.pank │ ├── print_99.pank │ ├── print_hello_world.pank │ ├── stdlib_math_e.pank │ ├── stdlib_math_pi.pank │ ├── stdlib_math_cos.pank │ ├── stdlib_math_sin.pank │ ├── stdlib_math_ceil.pank │ ├── stdlib_math_tan.pank │ ├── stdlib_big_add.pank │ ├── stdlib_math_abs.pank │ └── stdlib_big_new.pank ├── pyproject.toml ├── test_print.py ├── main.py ├── test_stdlib_big.py └── test_stdlib_math.py ├── zig_version.txt ├── web ├── serve ├── index.html ├── style.css └── script.js ├── images ├── icon.ico ├── pankti_128x.png ├── pankti_16x.ico ├── pankti_320x.png ├── pankti_32x.ico ├── pankti_32x.png ├── pankti_64x.ico ├── pankti_64x.png ├── pankti_96x.ico ├── pankti_header.png ├── bokbok_the_heron.png └── bokbok_the_heron.aseprite ├── windows ├── icon.ico ├── resource.h ├── windows.vcxproj.filters ├── windows.sln ├── windows.rc └── windows.vcxproj ├── stress.sh ├── sample ├── stdos.pank ├── stdstring.pank ├── array.pank ├── fib35.pank ├── stdbig.pank ├── stdmap.pank ├── map.pank ├── fib_iterative.pank ├── projecteular_solutions │ ├── 1.pank │ ├── 5.pank │ ├── 3.pank │ ├── 2.pank │ └── 4.pank ├── if_else.pank ├── fib_with_stdbig.pank └── stdmath.pank ├── runsamples.sh ├── extra └── pankti.desktop ├── examples └── function.pank ├── .github ├── workflows │ ├── zigtest.yml │ └── build_release.yml └── FUNDING.yml ├── notes ├── spec │ └── specification.md ├── cpank │ ├── import_system.txt │ └── old │ │ └── import_system.txt └── stdlib.md ├── a.pank ├── release.py ├── README.md ├── Makefile └── .gitignore /src/object_errors.zig: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /zig_version.txt: -------------------------------------------------------------------------------- 1 | 0.15.1 2 | -------------------------------------------------------------------------------- /tests/samples/stdlib_math_deg.pank: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/samples/stdlib_math_floor.pank: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/samples/stdlib_math_gcd.pank: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/samples/stdlib_math_lcm.pank: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/samples/stdlib_math_log.pank: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/samples/stdlib_math_log10.pank: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/samples/stdlib_math_logx.pank: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/samples/stdlib_math_num.pank: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/samples/stdlib_math_rad.pank: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/samples/stdlib_math_round.pank: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/samples/stdlib_math_sqrt.pank: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/samples/print_1.pank: -------------------------------------------------------------------------------- 1 | দেখাও(১) 2 | -------------------------------------------------------------------------------- /tests/samples/print_99.pank: -------------------------------------------------------------------------------- 1 | দেখাও(৯৯) 2 | -------------------------------------------------------------------------------- /web/serve: -------------------------------------------------------------------------------- 1 | #!/bin/env sh 2 | python -m http.server 8895 3 | -------------------------------------------------------------------------------- /tests/samples/print_hello_world.pank: -------------------------------------------------------------------------------- 1 | দেখাও("hello" + " world") 2 | -------------------------------------------------------------------------------- /tests/samples/stdlib_math_e.pank: -------------------------------------------------------------------------------- 1 | আনয়ন গণিত "গণিত" 2 | দেখাও(গণিত.ই() ) 3 | -------------------------------------------------------------------------------- /tests/samples/stdlib_math_pi.pank: -------------------------------------------------------------------------------- 1 | আনয়ন গণিত "গণিত" 2 | দেখাও(গণিত.পাই() ) 3 | -------------------------------------------------------------------------------- /images/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bauripalash/pankti/HEAD/images/icon.ico -------------------------------------------------------------------------------- /windows/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bauripalash/pankti/HEAD/windows/icon.ico -------------------------------------------------------------------------------- /images/pankti_128x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bauripalash/pankti/HEAD/images/pankti_128x.png -------------------------------------------------------------------------------- /images/pankti_16x.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bauripalash/pankti/HEAD/images/pankti_16x.ico -------------------------------------------------------------------------------- /images/pankti_320x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bauripalash/pankti/HEAD/images/pankti_320x.png -------------------------------------------------------------------------------- /images/pankti_32x.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bauripalash/pankti/HEAD/images/pankti_32x.ico -------------------------------------------------------------------------------- /images/pankti_32x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bauripalash/pankti/HEAD/images/pankti_32x.png -------------------------------------------------------------------------------- /images/pankti_64x.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bauripalash/pankti/HEAD/images/pankti_64x.ico -------------------------------------------------------------------------------- /images/pankti_64x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bauripalash/pankti/HEAD/images/pankti_64x.png -------------------------------------------------------------------------------- /images/pankti_96x.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bauripalash/pankti/HEAD/images/pankti_96x.ico -------------------------------------------------------------------------------- /images/pankti_header.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bauripalash/pankti/HEAD/images/pankti_header.png -------------------------------------------------------------------------------- /images/bokbok_the_heron.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bauripalash/pankti/HEAD/images/bokbok_the_heron.png -------------------------------------------------------------------------------- /images/bokbok_the_heron.aseprite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bauripalash/pankti/HEAD/images/bokbok_the_heron.aseprite -------------------------------------------------------------------------------- /stress.sh: -------------------------------------------------------------------------------- 1 | #!/bin/env bash 2 | 3 | clear 4 | for n in {1..100}; 5 | do 6 | make 7 | echo "-- $n --" 8 | done 9 | -------------------------------------------------------------------------------- /src/emfiles/about.txt: -------------------------------------------------------------------------------- 1 | Pankti Programming Language 2 | A Bengali Programming Language. 3 | 4 | Version: {s} 5 | 6 | Usage: 7 | pankti [FILENAME] 8 | -------------------------------------------------------------------------------- /sample/stdos.pank: -------------------------------------------------------------------------------- 1 | আনয়ন ও "ওএস" 2 | দেখাও(ও.নাম(), "\n") 3 | দেখাও(ও.আর্চ(), "\n") 4 | দেখাও(ও.ব্যবহারকারী(), "\n") 5 | দেখাও(ও.ঘর(), "\n") 6 | দেখাও(ও.বর্তমান(), "\n") 7 | -------------------------------------------------------------------------------- /tests/samples/stdlib_math_cos.pank: -------------------------------------------------------------------------------- 1 | আনয়ন গণিত "গণিত" 2 | দেখাও(গণিত.কস(৯০), "\n") 3 | দেখাও(গণিত.কস(1.5708), "\n") 4 | দেখাও(গণিত.কস(1.0472), "\n") 5 | দেখাও(গণিত.কস(0.575959), "\n") 6 | -------------------------------------------------------------------------------- /tests/samples/stdlib_math_sin.pank: -------------------------------------------------------------------------------- 1 | আনয়ন গণিত "গণিত" 2 | দেখাও(গণিত.সাইন(৯০), "\n") 3 | দেখাও(গণিত.সাইন(1.5708), "\n") 4 | দেখাও(গণিত.সাইন(1.0472), "\n") 5 | দেখাও(গণিত.সাইন(0.575959), "\n") 6 | -------------------------------------------------------------------------------- /runsamples.sh: -------------------------------------------------------------------------------- 1 | #! /bin/env sh 2 | 3 | export CPANK_EXE=./zig-out/bin/pankti 4 | 5 | for SAMPLE in sample/*.pank; do 6 | echo -en "\nRunning:" $SAMPLE "\n"; 7 | $CPANK_EXE $SAMPLE; 8 | done 9 | -------------------------------------------------------------------------------- /sample/stdstring.pank: -------------------------------------------------------------------------------- 1 | আনয়ন স "স্ট্রিং" 2 | 3 | দেখাও(স.ভাগ("হ্যালো.পৃথিবী." , "."), "\n") 4 | দেখাও(স.স্ট্রিং({"হ্যালো" : "পৃথিবী" , "নাম" : "পলাশ"}), "\n") 5 | দেখাও(স.ইউনিকোড(128122), "\n") 6 | -------------------------------------------------------------------------------- /tests/samples/stdlib_math_ceil.pank: -------------------------------------------------------------------------------- 1 | আনয়ন গণিত "গণিত" 2 | দেখাও(গণিত.সিল(1.2), "\n") 3 | দেখাও(গণিত.সিল(-99.৯৯), "\n") 4 | দেখাও(গণিত.সিল(-1.৯৯৯৯৯৯৯৯৯৯৯৯), "\n") 5 | দেখাও(গণিত.সিল(০.১), "\n") 6 | -------------------------------------------------------------------------------- /tests/samples/stdlib_math_tan.pank: -------------------------------------------------------------------------------- 1 | আনয়ন গণিত "গণিত" 2 | দেখাও(গণিত.ট্যান(৯০), "\n") 3 | দেখাও(গণিত.ট্যান(1.5708), "\n") 4 | দেখাও(গণিত.ট্যান(1.0472), "\n") 5 | দেখাও(গণিত.ট্যান(0.575959), "\n") 6 | -------------------------------------------------------------------------------- /extra/pankti.desktop: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env xdg-open 2 | [Desktop Entry] 3 | Name=Pankti 4 | Exec=/usr/local/bin/pankti 5 | Icon=/usr/local/share/pankti/icons/icon.ico 6 | Terminal=true 7 | Type=Application 8 | -------------------------------------------------------------------------------- /sample/array.pank: -------------------------------------------------------------------------------- 1 | ধরি ক = ["1", ২, "নমস্কার বিশ্ব"] 2 | দেখাও(ক) 3 | ক[0] = ১০০ #এখন ক এর প্রথম রাশি ১০০ (সংখ্যা) 4 | দেখাও(ক, "\n") 5 | ক[1] = ৫ # এখন ক এর দ্বিতীয় রাশি ৫ (সংখ্যা) 6 | দেখাও(ক[২][ক[1]], "\n") 7 | -------------------------------------------------------------------------------- /tests/samples/stdlib_big_add.pank: -------------------------------------------------------------------------------- 1 | আনয়ন বড় "বড়" 2 | দেখাও(বড়.যোগ(বড়.নতুন(3.14) , বড়.নতুন(৩.১৪)), "\n") 3 | দেখাও(বড়.যোগ(বড়.নতুন(100) , বড়.নতুন(200.2)), "\n") 4 | দেখাও(বড়.যোগ(বড়.নতুন("125") , বড়.নতুন("50")), "\n") 5 | -------------------------------------------------------------------------------- /tests/samples/stdlib_math_abs.pank: -------------------------------------------------------------------------------- 1 | আনয়ন গণিত "গণিত" 2 | দেখাও(গণিত.পরম(-১০০), "\n") 3 | দেখাও(গণিত.পরম(১১.০), "\n") 4 | দেখাও(গণিত.পরম(99), "\n") 5 | দেখাও(গণিত.পরম(-১৯৯.99), "\n") 6 | দেখাও(গণিত.পরম(৯৯.99), "\n") 7 | -------------------------------------------------------------------------------- /sample/fib35.pank: -------------------------------------------------------------------------------- 1 | kaj fib(n) 2 | if n < 2 then 3 | return n 4 | end 5 | 6 | return fib(n-2) + fib(n-1) 7 | end 8 | 9 | let start = clock() 10 | show(fib(35), "\n") 11 | show((clock() - start) / 1000) 12 | -------------------------------------------------------------------------------- /examples/function.pank: -------------------------------------------------------------------------------- 1 | কাজ ঘুমানো(নায়ক) 2 | দেখাও(নায়ক + " এখন ঘুমোচ্ছে!") 3 | শেষ 4 | 5 | ঘুমানো("পলাশ বাউরি") 6 | 7 | কাজ দ্বিগুণ(সংখ্যা) 8 | ফেরাও সংখ্যা * ২ 9 | শেষ 10 | 11 | দেখাও(দ্বিগুণ(৯৯৯)) 12 | 13 | -------------------------------------------------------------------------------- /sample/stdbig.pank: -------------------------------------------------------------------------------- 1 | আনয়ন ব "বড়" 2 | 3 | ধরি ক = ব.নতুন("1") 4 | ধরি খ = ব.নতুন("2") 5 | ধরি গ = ব.যোগ(ক , খ) 6 | ধরি ঘ = ব.বিয়োগ(গ, ক) 7 | 8 | দেখাও(ক, "\n") 9 | দেখাও(খ, "\n") 10 | দেখাও(গ, "\n") 11 | দেখাও(ঘ, "\n") 12 | -------------------------------------------------------------------------------- /sample/stdmap.pank: -------------------------------------------------------------------------------- 1 | আনয়ন ম "ম্যাপ" 2 | ধরি ক = {"নাম": "পলাশ" , ১:২} 3 | দেখাও(ক, "\n") 4 | 5 | দেখাও(ম.বর্তমান(ক , "নাম"), "\n") 6 | দেখাও(ম.বর্তমান(ক , ২), "\n") 7 | 8 | ধরি খ = ম.সূচক(ক) 9 | ধরি গ = ম.মান(ক) 10 | 11 | দেখাও(খ, "\n") 12 | দেখাও(গ, "\n") 13 | -------------------------------------------------------------------------------- /sample/map.pank: -------------------------------------------------------------------------------- 1 | ধরি তথ্য = {"নাম": "পলাশ"} 2 | দেখাও(তথ্য["নাম"]) 3 | 4 | কাজ নাচ() 5 | দেখাও(তথ্য["নাম"] + " নাচ করছে\n") 6 | শেষ 7 | 8 | তথ্য = { 9 | "নাম": "পলাশ", 10 | "দেশ": "ভারত", 11 | "ফোন":১০০, 12 | 1:২, 13 | ২:৩, 14 | "ক": নাচ 15 | } 16 | 17 | দেখাও(তথ্য, "\n") 18 | তথ্য["ক"]() 19 | -------------------------------------------------------------------------------- /sample/fib_iterative.pank: -------------------------------------------------------------------------------- 1 | কাজ ফিব(ন) 2 | ধরি ক = ০ 3 | ধরি খ = 1 4 | যদি ন <= ০ তাহলে 5 | ফেরাও ০ 6 | শেষ 7 | 8 | ধরি স = 1 9 | যতক্ষণ স < ন করো 10 | ধরি গ = ক + খ 11 | ক = খ 12 | খ = গ 13 | স = স + 1 14 | শেষ 15 | ফেরাও খ 16 | শেষ 17 | 18 | 19 | দেখাও(ফিব(৩৫), "\n") 20 | -------------------------------------------------------------------------------- /sample/projecteular_solutions/1.pank: -------------------------------------------------------------------------------- 1 | # ১০০০ এর কম সমস্ত সংখ্যার যোগফল যাদের ৩ বা ৫ দিয়ে ভাগ করলে ভাগফল শূন্য হয় 2 | # https://projecteuler.net/problem=1 3 | 4 | ধরি ক = ১ 5 | ধরি ফল = ০ 6 | যতক্ষণ ক < ১০০০ করো 7 | যদি ক % ৩ == ০ বা ক % ৫ == ০ তাহলে 8 | ফল = ফল + ক 9 | শেষ 10 | 11 | ক = ক + ১ 12 | শেষ 13 | 14 | দেখাও(ফল) 15 | -------------------------------------------------------------------------------- /sample/if_else.pank: -------------------------------------------------------------------------------- 1 | ধরি ক = সত্যি 2 | ধরি খ = মিথ্যা 3 | 4 | যদি ক তাহলে 5 | দেখাও(সত্যি, "\n") 6 | নাহলে 7 | দেখাও(মিথ্যা, "\n") 8 | শেষ 9 | 10 | যদি খ তাহলে 11 | দেখাও(সত্যি, "\n") 12 | নাহলে 13 | দেখাও(মিথ্যা, "\n") 14 | শেষ 15 | 16 | যদি !খ তাহলে 17 | দেখাও(!সত্যি, "\n") 18 | নাহলে 19 | দেখাও(!মিথ্যা, "\n") 20 | শেষ 21 | -------------------------------------------------------------------------------- /tests/samples/stdlib_big_new.pank: -------------------------------------------------------------------------------- 1 | আনয়ন বড় "বড়" 2 | দেখাও(বড়.নতুন("100"), "\n") 3 | দেখাও(বড়.নতুন("9999"), "\n") 4 | দেখাও(বড়.নতুন(100), "\n") 5 | দেখাও(বড়.নতুন(9999), "\n") 6 | দেখাও(বড়.নতুন(3.14), "\n") 7 | দেখাও(বড়.নতুন(1000000000000000000000000000), "\n") 8 | দেখাও(বড়.নতুন("1000000000000000000000000000"), "\n") 9 | দেখাও(বড়.নতুন("3.14"), "\n") 10 | -------------------------------------------------------------------------------- /src/pankti.zig: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) Palash Bauri 3 | // 4 | // This Source Code Form is subject to the terms of the Mozilla Public 5 | // License, v. 2.0. If a copy of the MPL was not distributed with this 6 | // file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | // 8 | // SPDX-License-Identifier: MPL-2.0 9 | 10 | pub const build_options = @import("build_options"); 11 | -------------------------------------------------------------------------------- /tests/pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.poetry] 2 | name = "tests" 3 | version = "0.1.0" 4 | description = "Test Runner for Pankti Programming Language" 5 | authors = ["Palash Bauri "] 6 | readme = "README.md" 7 | 8 | [tool.poetry.dependencies] 9 | python = "^3.11" 10 | 11 | 12 | [build-system] 13 | requires = ["poetry-core"] 14 | build-backend = "poetry.core.masonry.api" 15 | -------------------------------------------------------------------------------- /sample/fib_with_stdbig.pank: -------------------------------------------------------------------------------- 1 | আনয়ন বড় "বড়" 2 | 3 | কাজ ফিব(ন) 4 | ধরি ক = বড়.নতুন("0") 5 | ধরি খ = বড়.নতুন("1") 6 | 7 | যদি ন <= ০ তাহলে 8 | ফেরাও ০ 9 | শেষ 10 | 11 | ধরি স = 1 12 | যতক্ষণ স < ন করো 13 | ধরি গ = বড়.যোগ(ক, খ) 14 | ক = খ 15 | খ = গ 16 | স = স + 1 17 | শেষ 18 | 19 | ফেরাও খ 20 | শেষ 21 | 22 | দেখাও(ফিব(১০০০), "\n") 23 | -------------------------------------------------------------------------------- /src/vm_errors.zig: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) Palash Bauri 3 | // 4 | // This Source Code Form is subject to the terms of the Mozilla Public 5 | // License, v. 2.0. If a copy of the MPL was not distributed with this 6 | // file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | // 8 | // SPDX-License-Identifier: MPL-2.0 9 | 10 | pub const RUNTIME_ERROR = "প্রোগ্রাম চলাকালীন গোলযোগ"; 11 | pub const NONG_LINE = "নং লাইনে"; 12 | pub const SUB_TYPE_MISMATCH = "{s}({s}) এবং {s}({s}) এর মধ্যে বিয়োগ করা সম্ভব নয়!"; 13 | -------------------------------------------------------------------------------- /windows/resource.h: -------------------------------------------------------------------------------- 1 | //{{NO_DEPENDENCIES}} 2 | // Microsoft Visual C++ generated include file. 3 | // Used by windows.rc 4 | // 5 | #define IDI_ICON1 101 6 | 7 | // Next default values for new objects 8 | // 9 | #ifdef APSTUDIO_INVOKED 10 | #ifndef APSTUDIO_READONLY_SYMBOLS 11 | #define _APS_NEXT_RESOURCE_VALUE 103 12 | #define _APS_NEXT_COMMAND_VALUE 40001 13 | #define _APS_NEXT_CONTROL_VALUE 1001 14 | #define _APS_NEXT_SYMED_VALUE 101 15 | #endif 16 | #endif 17 | -------------------------------------------------------------------------------- /.github/workflows/zigtest.yml: -------------------------------------------------------------------------------- 1 | name: Tests 2 | 3 | on: 4 | push: 5 | branches: [ "main" ] 6 | pull_request: 7 | branches: [ "main" ] 8 | schedule: 9 | - cron: '0 0 * * 0' 10 | 11 | jobs: 12 | test: 13 | strategy: 14 | matrix: 15 | os: [ubuntu-latest, windows-latest, macos-latest] 16 | runs-on: ${{matrix.os}} 17 | steps: 18 | - uses: actions/checkout@v4 19 | - uses: mlugg/setup-zig@v1 20 | with: 21 | version: '2024.11.0-mach' 22 | - run: | 23 | zig build --fetch 24 | make test 25 | 26 | -------------------------------------------------------------------------------- /sample/stdmath.pank: -------------------------------------------------------------------------------- 1 | আনয়ন গ "গণিত" 2 | দেখাও(গ.পাই(), "\n"); 3 | দেখাও(গ.ই(), "\n"); 4 | দেখাও(গ.বর্গমূল(10.9999), "\n") 5 | দেখাও(গ.লগদশ(100), "\n") 6 | দেখাও(গ.লগ(100), "\n") 7 | দেখাও(গ.লগবেস(10 , 100), "\n") 8 | দেখাও(গ.গসাগু(10, 100), "\n") 9 | দেখাও(গ.লসাগু(3,6), "\n") 10 | দেখাও(গ.সাইন(100), "\n") 11 | দেখাও(গ.কস(100), "\n") 12 | দেখাও(গ.ট্যান(100), "\n") 13 | দেখাও(গ.ডিগ্রি(100), "\n") 14 | দেখাও(গ.রেডিয়ান(90), "\n") 15 | দেখাও(গ.সংখ্যা("123456"), "\n") 16 | দেখাও(গ.পরম(-99), "\n") 17 | দেখাও(গ.রাউন্ড(9.3), "\n") 18 | দেখাও(গ.ফ্লোর(8.5), "\n") 19 | দেখাও(গ.সিল(99.99), "\n") 20 | -------------------------------------------------------------------------------- /notes/spec/specification.md: -------------------------------------------------------------------------------- 1 | # [DRAFT]Pankti Programming Language Specification 2 | 3 | ## Abstract 4 | This document specifies the language behavior and sementics of Pankti 5 | Programming Language and will serve as guide for developing of Pankti 6 | implmenetation. This document covers the grammar and sementics this language 7 | as well as standard library. 8 | 9 | This specification is a Draft and may and will change without notice. This 10 | document can be found at the source code repository of Cpank, the reference 11 | implementation of Pankti. 12 | 13 | ## Language 14 | ### Keywords 15 | TODO: 16 | -------------------------------------------------------------------------------- /tests/test_print.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from .main import run_pankti as rp 4 | 5 | cases_numbers = [ 6 | ["print_1" , "1"], 7 | ["print_99" , "99"], 8 | ] 9 | 10 | cases_string = [ 11 | ["print_hello_world" , "hello world"], 12 | ] 13 | 14 | class TestPrint(unittest.TestCase): 15 | def test_number(self): 16 | for item in cases_numbers: 17 | self.assertEqual(rp(item[0]), item[1]) 18 | 19 | def test_string(self): 20 | for item in cases_string: 21 | self.assertEqual(rp(item[0]), item[1]) 22 | 23 | 24 | if __name__ == "__main__": 25 | unittest.main() 26 | -------------------------------------------------------------------------------- /sample/projecteular_solutions/5.pank: -------------------------------------------------------------------------------- 1 | আনয়ন স্ট্রিং "স্ট্রিং" 2 | আনয়ন গণিত "গণিত" 3 | 4 | কাজ লসাগু(ল) 5 | ধরি ক = ০ 6 | ধরি উত্তর = ১ 7 | যতক্ষণ ক < len(ল) করো 8 | ধরি ম = ল[ক] 9 | উত্তর = গণিত.ফ্লোর(উত্তর * ম / গণিত.গসাগু(উত্তর, ম)) 10 | ক = ক + ১ 11 | শেষ 12 | 13 | ফেরাও(উত্তর) 14 | 15 | শেষ 16 | 17 | কাজ প্রথম() 18 | ধরি ল = স্ট্রিং.ভাগ("1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20", ",") 19 | ধরি ক = ০ 20 | যতক্ষণ ক < len(ল) করো 21 | ল[ক] = গণিত.সংখ্যা(ল[ক]) 22 | ক = ক + ১ 23 | শেষ 24 | দেখাও((লসাগু(ল))) 25 | শেষ 26 | 27 | প্রথম() 28 | -------------------------------------------------------------------------------- /src/openfile.zig: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) Palash Bauri 3 | // 4 | // This Source Code Form is subject to the terms of the Mozilla Public 5 | // License, v. 2.0. If a copy of the MPL was not distributed with this 6 | // file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | // 8 | // SPDX-License-Identifier: MPL-2.0 9 | 10 | const std = @import("std"); 11 | const print = std.debug.print; 12 | 13 | pub fn openfile(path: []const u8, aloc: std.mem.Allocator) ![]u8 { 14 | var f = try std.fs.cwd().openFile(path, .{}); 15 | defer f.close(); 16 | 17 | const read_buf = try f.readToEndAlloc(aloc, std.math.maxInt(usize)); 18 | return read_buf; 19 | } 20 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | github: [bauripalash] # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 3 | patreon: # Replace with a single Patreon username 4 | open_collective: # Replace with a single Open Collective username 5 | ko_fi: palash # Replace with a single Ko-fi username 6 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 7 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 8 | issuehunt: # Replace with a single IssueHunt username 9 | otechie: # Replace with a single Otechie username 10 | custom: ['https://paypal.me/bauripalash'] 11 | -------------------------------------------------------------------------------- /sample/projecteular_solutions/3.pank: -------------------------------------------------------------------------------- 1 | #https://projecteuler.net/problem=3 2 | 3 | আনয়ন গণিত "গণিত" 4 | 5 | কাজ ছোট(ন) 6 | যদি ন < ২ তাহলে ফেরাও ০ শেষ 7 | 8 | ধরি ক = ২ 9 | ধরি খ = গণিত.বর্গমূল(ন) 10 | 11 | যতক্ষণ ক != খ করো 12 | যদি ন % ক == ০ তাহলে 13 | ফেরাও ক 14 | শেষ 15 | ক = ক + ১ 16 | শেষ 17 | 18 | ফেরাও ন 19 | শেষ 20 | 21 | কাজ গণনা() 22 | ধরি ন = 600851475143 23 | যতক্ষণ সত্যি করো 24 | ধরি ক = ছোট(ন) 25 | 26 | যদি ক < ন তাহলে 27 | ন = গণিত.ফ্লোর(ন / ক) 28 | নাহলে 29 | ফেরাও ন 30 | শেষ 31 | শেষ 32 | শেষ 33 | 34 | কাজ প্রথম() 35 | ধরি ক = গণনা() 36 | দেখাও(ক) 37 | শেষ 38 | 39 | প্রথম() 40 | -------------------------------------------------------------------------------- /src/flags.zig: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) Palash Bauri 3 | // 4 | // This Source Code Form is subject to the terms of the Mozilla Public 5 | // License, v. 2.0. If a copy of the MPL was not distributed with this 6 | // file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | // 8 | // SPDX-License-Identifier: MPL-2.0 9 | 10 | pub const NO_GC = false; 11 | pub const DEBUG_GC = false; 12 | pub const STRESS_GC = false; 13 | pub const DEBUG_STACK = false; 14 | pub const DEBUG_GLOBS = false; 15 | pub const DEBUG = true; 16 | pub const DEBUG_FREE_OBJECTS = false; 17 | pub const DEBUG_NEW_OBJECTS = false; 18 | pub const DEBUG_LEXER = false; 19 | pub const DEBUG_OPCODE = false; 20 | pub const DEBUG_VM_RESULT = false; 21 | pub const DEBUG_FINAL = false; 22 | -------------------------------------------------------------------------------- /sample/projecteular_solutions/2.pank: -------------------------------------------------------------------------------- 1 | #https://projecteuler.net/problem=2 2 | 3 | কাজ ফিব(ন) 4 | ধরি ক = ০ 5 | ধরি খ = ১ 6 | 7 | যদি ন < ০ তাহলে ফেরাও ০ শেষ 8 | যদি ন == ১ তাহলে ফেরাও খ শেষ 9 | 10 | ধরি স = ১; 11 | 12 | যতক্ষণ স < ন করো 13 | ধরি গ = ক + খ 14 | ক = খ 15 | খ = গ 16 | স = স + ১ 17 | শেষ 18 | 19 | ফেরাও খ 20 | 21 | শেষ 22 | 23 | কাজ প্রথম() 24 | ধরি ফল = ০ 25 | ধরি ক = ০ 26 | 27 | 28 | যতক্ষণ সত্যি করো 29 | ধরি ম = ফিব(ক) 30 | 31 | যদি ম > ৪০০০০০০ তাহলে 32 | ভাঙো 33 | শেষ 34 | 35 | যদি ম % ২ == ০ তাহলে 36 | ফল = ফল + ম 37 | শেষ 38 | 39 | ক = ক + ১ 40 | শেষ 41 | 42 | দেখাও(ফল) 43 | শেষ 44 | 45 | প্রথম() 46 | -------------------------------------------------------------------------------- /.github/workflows/build_release.yml: -------------------------------------------------------------------------------- 1 | name: Build Release 2 | 3 | on: 4 | push: 5 | tags: 6 | - "*" 7 | 8 | jobs: 9 | test: 10 | strategy: 11 | matrix: 12 | os: [ubuntu-latest] 13 | runs-on: ${{matrix.os}} 14 | steps: 15 | - uses: actions/checkout@v4 16 | - uses: mlugg/setup-zig@v1 17 | with: 18 | version: '2024.11.0-mach' 19 | - name: Build Release 20 | run: | 21 | make release 22 | - name: Upload Artifacts 23 | uses: actions/upload-artifact@v4 24 | with: 25 | name: pankti-linux-win-32_64 26 | path: | 27 | dist/pankti-linux64 28 | dist/pankti-linux32 29 | dist/pankti-win64.exe 30 | dist/pankti-win32.exe 31 | 32 | -------------------------------------------------------------------------------- /tests/main.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | import subprocess 4 | path = os.path 5 | 6 | 7 | PANKTI_EXE = path.join(os.curdir , "zig-out/bin/pankti") 8 | 9 | if sys.platform == "win32": 10 | PANKTI_EXE += ".exe" 11 | 12 | def get_file_path(name : str) -> str: 13 | return path.join(os.curdir , "tests" , "samples" , name) + ".pank" 14 | 15 | def run_pankti(src : str) -> str: 16 | p = get_file_path(src) 17 | #print(PANKTI_EXE) 18 | if not path.exists(PANKTI_EXE): 19 | print("Pankti Exe not found!") 20 | raise FileNotFoundError 21 | if not path.exists(p): 22 | print("Sample File not found!") 23 | raise FileNotFoundError 24 | 25 | res = subprocess.run([PANKTI_EXE , p] , stdout=subprocess.PIPE) 26 | return res.stdout.decode().rstrip('\n') 27 | -------------------------------------------------------------------------------- /src/stdlib/os_errors.zig: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) Palash Bauri 3 | // 4 | // This Source Code Form is subject to the terms of the Mozilla Public 5 | // License, v. 2.0. If a copy of the MPL was not distributed with this 6 | // file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | // 8 | // SPDX-License-Identifier: MPL-2.0 9 | 10 | pub const OS_NAME_ARG_NOT_ZERO = "ওএস -এর নাম() কাজটি কোনো চলরাশি গ্রহণ করে কিন্তু {d}টি দেওয়া হয়েছে"; 11 | pub const OS_ARCH_ARG_NOT_ZERO = "ওএস -এর আর্চ() কাজটি কোনো চলরাশি গ্রহণ করে কিন্তু {d}টি দেওয়া হয়েছে"; 12 | pub const OS_USERNAME_ARG_NOT_ZERO = "ওএস -এর ব্যবহারকারী() কাজটি কোনো চলরাশি গ্রহণ করে কিন্তু {d}টি দেওয়া হয়েছে"; 13 | pub const OS_HOMEDIR_ARG_NOT_ZERO = "ওএস -এর ঘর() কাজটি কোনো চলরাশি গ্রহণ করে কিন্তু {d}টি দেওয়া হয়েছে"; 14 | pub const OS_CURDIR_ARG_NOT_ZERO = "ওএস -এর বর্তমান() কাজটি কোনো চলরাশি গ্রহণ করে কিন্তু {d}টি দেওয়া হয়েছে"; 15 | -------------------------------------------------------------------------------- /tests/test_stdlib_big.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | import math 3 | from .main import run_pankti as rp 4 | 5 | 6 | big_new = "stdlib_big_new" 7 | big_add = "stdlib_big_add" 8 | 9 | 10 | class TestStdlibBig(unittest.TestCase): 11 | def test_big_new(self): 12 | r = rp(big_new).splitlines() 13 | self.assertEqual(r[0], "100") 14 | self.assertEqual(r[1], "9999") 15 | self.assertEqual(r[2], "100") 16 | self.assertEqual(r[3], "9999") 17 | self.assertEqual(r[4], "3") 18 | self.assertEqual(r[5], "9223372036854775807") 19 | self.assertEqual(r[6], "1000000000000000000000000000") 20 | 21 | def test_big_add(self): 22 | r = rp(big_add).splitlines() 23 | self.assertEqual(r[0] , "6") 24 | self.assertEqual(r[1] , "300") 25 | self.assertEqual(r[2] , "175") 26 | 27 | 28 | if __name__ == "__main__": 29 | unittest.main() 30 | -------------------------------------------------------------------------------- /windows/windows.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | -------------------------------------------------------------------------------- /sample/projecteular_solutions/4.pank: -------------------------------------------------------------------------------- 1 | আনয়ন স্ট্রিং "স্ট্রিং" 2 | 3 | কাজ প্যালিড্রোম(ন) 4 | ধরি স = স্ট্রিং.স্ট্রিং(ন) 5 | ধরি নিম্ন = ০ 6 | ধরি উচ্চ = len(স) - ১ 7 | 8 | যতক্ষণ নিম্ন < উচ্চ করো 9 | যদি স[নিম্ন] != স[উচ্চ] তাহলে 10 | ফেরাও মিথ্যা 11 | শেষ 12 | 13 | নিম্ন = নিম্ন + ১ 14 | উচ্চ = উচ্চ - ১ 15 | শেষ 16 | ফেরাও সত্যি 17 | শেষ 18 | 19 | কাজ বড়() 20 | ধরি বৃহত্তম = ০ 21 | ধরি ক = 999 22 | 23 | যতক্ষণ ক > 900 করো 24 | ধরি খ = ক 25 | যতক্ষণ খ > 900 করো 26 | ধরি গুন = খ * ক 27 | যদি প্যালিড্রোম(গুন) এবং গুন > বৃহত্তম তাহলে 28 | বৃহত্তম = ক * খ 29 | শেষ 30 | খ = খ - ১ 31 | শেষ 32 | ক = ক - ১ 33 | শেষ 34 | 35 | ফেরাও বৃহত্তম 36 | শেষ 37 | 38 | কাজ প্রথম() 39 | ধরি উত্তর = বড়() 40 | দেখাও("উত্তর->") 41 | দেখাও(উত্তর) 42 | শেষ 43 | 44 | প্রথম() 45 | -------------------------------------------------------------------------------- /a.pank: -------------------------------------------------------------------------------- 1 | #show(১.৯৮) 2 | #show("hello", "\n", "world\n") 3 | show("<\u09e6>","\n") 4 | show("X\U0001f418", "\n") 5 | let a = "palash" 6 | let b = "পলাশ" 7 | show(a,"\n") 8 | show(b, "\n") 9 | show(a[2], "\n") 10 | show(b[3], "\n") 11 | show("\x61","\n") 12 | show("\xe0\xa6\xaa\xe0\xa6\xb2\xe0\xa6\xbe\xe0\xa6\xb6", "\n") 13 | show("\U000009aa\U000009b2\U000009be\U000009b6", "\n") 14 | 15 | আনয়ন বড় "বড়" 16 | 17 | show("Mangao", "\n") 18 | ধরি ক = বড়.নতুন(১০০) 19 | 20 | ধরি খ = বড়.নতুন(২০০) 21 | 22 | দেখাও(ক, "\n") 23 | 24 | show("Mangao", "\n") 25 | দেখাও(খ, "\n") 26 | 27 | ধরি গ = বড়.যোগ(ক, খ) 28 | ধরি ঘ = বড়.বিয়োগ(ক, খ) 29 | 30 | দেখাও(গ, "\n") 31 | দেখাও(ঘ, "\n") 32 | 33 | ধরি প = বড়.গুন(ক, খ) 34 | ধরি ফ = বড়.ভাগ(খ, ক) 35 | 36 | দেখাও(প, "\n") 37 | দেখাও(ফ, "\n") 38 | 39 | ধরি ব = বড়.বর্গমূল(খ) 40 | দেখাও(ব, "\n") 41 | 42 | ধরি চ = বড়.নতুন("100") 43 | 44 | দেখাও(ক == খ) 45 | দেখাও(ক == চ) 46 | 47 | show("100.3") 48 | 49 | #বড়.নতুন("3.14") 50 | বড়.নতুন(100000000000000000000) 51 | -------------------------------------------------------------------------------- /src/stdlib/string_errors.zig: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) Palash Bauri 3 | // 4 | // This Source Code Form is subject to the terms of the Mozilla Public 5 | // License, v. 2.0. If a copy of the MPL was not distributed with this 6 | // file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | // 8 | // SPDX-License-Identifier: MPL-2.0 9 | 10 | pub const STR_STRING_ACCEPTS_SINGLE_ARG = "স্ট্রিং(...) কাজটি মাত্র একটি চলরাশি গ্রহণ করে কিন্তু {d}টি দেওয়া হয়েছে"; 11 | pub const STR_SPLIT_ACCEPTS_TWO_ARGS = "ভাগ(...) কাজটি মাত্র দুটি চলরাশি গ্রহণ করে কিন্তু {d}টি দেওয়া হয়েছে"; 12 | pub const STR_SPLIT_NOT_STRING_ARGS = "ভাগ(...) কাজটিতে দেওয়া দুটি চলরাশিকেই স্ট্রিং হতে হবে কিন্তু পাওয়া গেল - {s}({s}) এবং {s}({s})"; 13 | 14 | pub const STR_SPLIT_INT_CONVERT_A_ERROR = "অভ্যন্তরীণ গোলযোগ; স্ট্রিং ভাগ(...) কাজে গোলযোগ দেখানোর সময় প্রথম রাশিকে স্ট্রিং-এ পরিবর্তন করা সম্ভব হয়নি।"; 15 | pub const STR_SPLIT_INT_CONVERT_B_ERROR = "অভ্যন্তরীণ গোলযোগ; স্ট্রিং ভাগ কাজে গোলযোগ দেখানোর সময় দ্বিতীয় রাশিকে স্ট্রিং-এ পরিবর্তন করা সম্ভব হয়নি।"; 16 | -------------------------------------------------------------------------------- /src/bengali/names.zig: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) Palash Bauri 3 | // 4 | // This Source Code Form is subject to the terms of the Mozilla Public 5 | // License, v. 2.0. If a copy of the MPL was not distributed with this 6 | // file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | // 8 | // SPDX-License-Identifier: MPL-2.0 9 | 10 | pub const simpleNameObjString = "স্ট্রিং"; 11 | pub const simpleNameObjFunction = "কাজ"; 12 | pub const simpleNameObjNativeFunc = "সাধারন কাজ"; 13 | pub const simpleNameObjClosure = "ক্লোজার"; 14 | pub const simpleNameObjUpvalue = "ক্লোজার চলরাশি"; 15 | pub const simpleNameObjArray = "তালিকা"; 16 | pub const simpleNameObjHmap = "হ্যাশম্যাপ"; 17 | pub const simpleNameObjError = "গোলযোগ"; 18 | pub const simpleNameObjBigint = "বড়সংখ্যা"; 19 | pub const simpleNameObjModule = "মডিউল"; 20 | 21 | pub const simpleNameNumber = "সংখ্যা"; 22 | pub const simpleNameBool = "বুলিয়ান"; 23 | pub const simpleNameNil = "নিল"; 24 | pub const simpleNameObject = "অবজেক্ট"; 25 | pub const simpleNameUnknown = "অজানা"; 26 | -------------------------------------------------------------------------------- /src/writer.zig: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) Palash Bauri 3 | // 4 | // This Source Code Form is subject to the terms of the Mozilla Public 5 | // License, v. 2.0. If a copy of the MPL was not distributed with this 6 | // file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | // 8 | // SPDX-License-Identifier: MPL-2.0 9 | 10 | const std = @import("std"); 11 | const utils = @import("utils.zig"); 12 | 13 | pub const OutWriter = struct { 14 | pub const WriteFunction = *const fn (bts: []const u8) void; 15 | wfn: WriteFunction, 16 | 17 | const Self = @This(); 18 | pub fn new(wf: WriteFunction) Self { 19 | return OutWriter{ 20 | .wfn = wf, 21 | }; 22 | } 23 | 24 | pub const OutWriterError = error{}; 25 | 26 | pub fn write(self: Self, bts: []const u8) OutWriterError!usize { 27 | self.wfn(bts); 28 | return bts.len; 29 | } 30 | 31 | pub const Writer = std.io.Writer(OutWriter, OutWriterError, write); 32 | 33 | pub fn writer(self: Self) Writer { 34 | return .{ 35 | .context = self, 36 | }; 37 | } 38 | }; 39 | 40 | pub const PanWriter = if (utils.IS_WASM) OutWriter.Writer else std.fs.File.Writer; 41 | -------------------------------------------------------------------------------- /src/bengali/bn.zig: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) Palash Bauri 3 | // 4 | // This Source Code Form is subject to the terms of the Mozilla Public 5 | // License, v. 2.0. If a copy of the MPL was not distributed with this 6 | // file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | // 8 | // SPDX-License-Identifier: MPL-2.0 9 | 10 | pub const BN_NUM_0 = 0x09E6; 11 | pub const BN_NUM_1 = 0x09E7; 12 | pub const BN_NUM_2 = 0x09E8; 13 | pub const BN_NUM_3 = 0x09E9; 14 | pub const BN_NUM_4 = 0x09EA; 15 | pub const BN_NUM_5 = 0x09EB; 16 | pub const BN_NUM_6 = 0x09EC; 17 | pub const BN_NUM_7 = 0x09ED; 18 | pub const BN_NUM_8 = 0x09EE; 19 | pub const BN_NUM_9 = 0x09EF; 20 | 21 | pub const BN_RANGE_START = 0x0980; 22 | pub const BN_RANGE_END = 0x09FE; 23 | 24 | /// Cheks if `c`, a UTF-32 encoded `char` is a valid bengali number 25 | pub inline fn isBnNumber(c: u32) bool { 26 | return c >= BN_NUM_0 and c <= BN_NUM_9; 27 | } 28 | 29 | /// Check if `c` is in bengali unicode range; 30 | /// Doesn't check for invalid or reserved chars 31 | pub inline fn isBnChar(c: u32) bool { 32 | return c >= BN_RANGE_START and c <= BN_RANGE_END; 33 | } 34 | 35 | pub inline fn bnToEnNum(c: u21) u21 { 36 | return switch (c) { 37 | BN_NUM_0 => '0', 38 | BN_NUM_1 => '1', 39 | BN_NUM_2 => '2', 40 | BN_NUM_3 => '3', 41 | BN_NUM_4 => '4', 42 | BN_NUM_5 => '5', 43 | BN_NUM_6 => '6', 44 | BN_NUM_7 => '7', 45 | BN_NUM_8 => '8', 46 | BN_NUM_9 => '9', 47 | else => c, 48 | }; 49 | } 50 | -------------------------------------------------------------------------------- /web/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Pankti Web Play 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 16 |
17 | 18 |
19 |
20 | 28 |
29 | 30 |
31 | 32 | 33 |
34 | 35 |
36 | 45 |
46 | 47 |
48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /src/khataapi.zig: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) Palash Bauri 3 | // 4 | // This Source Code Form is subject to the terms of the Mozilla Public 5 | // License, v. 2.0. If a copy of the MPL was not distributed with this 6 | // file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | // 8 | // SPDX-License-Identifier: MPL-2.0 9 | 10 | const std = @import("std"); 11 | const Gc = @import("gc.zig").Gc; 12 | const utils = @import("utils.zig"); 13 | const Vm = @import("vm.zig").Vm; 14 | 15 | pub export fn freeCode(src: [*c]u8, len: u32) void { 16 | // Does this even work ? 17 | std.heap.c_allocator.free(src[0..len]); 18 | } 19 | 20 | const InitBufferCap = 4096; 21 | 22 | pub export fn runCode(src: [*]const u8, len: u32) callconv(.c) [*c]u8 { 23 | const handyAl = std.heap.c_allocator; 24 | const gcAl = std.heap.c_allocator; 25 | var result = std.fmt.allocPrint(handyAl, "error", .{}) catch return null; 26 | 27 | const rawSrc = src[0..len]; 28 | 29 | var gc = Gc.new(gcAl, handyAl) catch { 30 | return result.ptr; 31 | }; 32 | 33 | //var warr = std.ArrayList(u8).initCapacity(gc.hal(), InitBufferCap) catch return null; 34 | var warr = std.Io.Writer.Allocating.initCapacity(gc.hal(), InitBufferCap) catch return null; 35 | 36 | gc.bootWithWriter(&warr.writer, &warr.writer); 37 | 38 | var myVm = Vm.newVm(gc.hal()) catch { 39 | return result.ptr; 40 | }; 41 | 42 | myVm.bootVm(gc); 43 | 44 | const vmResult = myVm.interpret(rawSrc); 45 | 46 | myVm.freeVm(gc.hal()); 47 | 48 | switch (vmResult) { 49 | .Ok => { 50 | handyAl.free(result); 51 | result = std.fmt.allocPrint(handyAl, "{s}", .{warr.toArrayList().items}) catch return null; 52 | return result.ptr; 53 | }, 54 | .RuntimeError => return result.ptr, 55 | .CompileError => return result.ptr, 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/ansicolors.zig: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) Palash Bauri 3 | // 4 | // This Source Code Form is subject to the terms of the Mozilla Public 5 | // License, v. 2.0. If a copy of the MPL was not distributed with this 6 | // file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | // 8 | // SPDX-License-Identifier: MPL-2.0 9 | 10 | const std = @import("std"); 11 | const writer = @import("writer.zig"); 12 | pub const ANSI_COLOR_BLACK = "\x1b[30m"; 13 | pub const ANSI_COLOR_RED = "\x1b[31m"; 14 | pub const ANSI_COLOR_GREEN = "\x1b[32m"; 15 | pub const ANSI_COLOR_YELLOW = "\x1b[33m"; 16 | pub const ANSI_COLOR_BLUE = "\x1b[34m"; 17 | pub const ANSI_COLOR_PURPLE = "\x1b[35m"; 18 | pub const ANSI_COLOR_CYAN = "\x1b[36m"; 19 | pub const ANSI_COLOR_WHITE = "\x1b[37m"; 20 | pub const ANSI_COLOR_RESET = "\x1b[0m"; 21 | 22 | pub fn TermColor(color: u8, w: *std.io.Writer) void { 23 | switch (color) { 24 | 'B' => { 25 | w.print("{s}", .{ANSI_COLOR_BLACK}) catch return; 26 | }, 27 | 'r' => { 28 | w.print("{s}", .{ANSI_COLOR_RED}) catch return; 29 | }, 30 | 'g' => { 31 | w.print("{s}", .{ANSI_COLOR_GREEN}) catch return; 32 | }, 33 | 'y' => { 34 | w.print("{s}", .{ANSI_COLOR_YELLOW}) catch return; 35 | }, 36 | 'b' => { 37 | w.print("{s}", .{ANSI_COLOR_BLUE}) catch return; 38 | }, 39 | 'p' => { 40 | w.print("{s}", .{ANSI_COLOR_PURPLE}) catch return; 41 | }, 42 | 'c' => { 43 | w.print("{s}", .{ANSI_COLOR_CYAN}) catch return; 44 | }, 45 | 'w' => { 46 | w.print("{s}", .{ANSI_COLOR_WHITE}) catch return; 47 | }, 48 | else => { 49 | return; 50 | }, 51 | } 52 | } 53 | 54 | pub fn ResetColor(w: *std.io.Writer) void { 55 | w.print("{s}", .{ANSI_COLOR_RESET}) catch return; 56 | } 57 | -------------------------------------------------------------------------------- /release.py: -------------------------------------------------------------------------------- 1 | #! /bin/env python3 2 | 3 | from typing import List 4 | import hashlib 5 | import os 6 | import subprocess 7 | from zipfile import ZipFile 8 | import zipfile 9 | 10 | DIST_PATH = "dist" 11 | 12 | def gen_sum(filepath : str) -> None: 13 | exe_file = os.path.join(os.curdir , DIST_PATH, filepath) 14 | csum_file = exe_file + ".sha512" 15 | with open(exe_file , "rb") as f: 16 | bts = f.read() 17 | rh = hashlib.sha512(bts); 18 | with open(csum_file , "w") as wf: 19 | wf.write(f"{rh.hexdigest()} {filepath}") 20 | print("[*] Created Checksum File " + csum_file) 21 | 22 | def build_release() -> bool: 23 | result = subprocess.run(["make", "release"], 24 | stdout=subprocess.PIPE, 25 | stderr=subprocess.PIPE) 26 | 27 | return result.returncode == 0 28 | 29 | def create_zip(filenames : List[str], output : str) -> bool: 30 | 31 | with ZipFile(output , mode="w", compression=zipfile.ZIP_DEFLATED) as z: 32 | for item in filenames: 33 | z.write(os.path.join(DIST_PATH, item), compresslevel=9) 34 | 35 | return True 36 | 37 | def main(): 38 | release_files = ["pankti-linux64", 39 | "pankti-linux32", 40 | "pankti-win32.exe", 41 | "pankti-win64.exe"] 42 | print("[+] Building Release") 43 | 44 | ok = build_release() 45 | 46 | if not ok: 47 | print("[X] Failed to build release!") 48 | exit(1) 49 | 50 | 51 | print("[+] Finished Building Release") 52 | 53 | 54 | for item in release_files: 55 | gen_sum(item) 56 | 57 | print("[+] Creating Zip Files") 58 | linux_zip = os.path.join(DIST_PATH, "pankti-linux.zip") 59 | print(f"[*] Zipping Linux Exes : {linux_zip}") 60 | create_zip(release_files[0:2], linux_zip) 61 | 62 | win_zip = os.path.join(DIST_PATH, "pankti-win.zip") 63 | print(f"[*] Zipping Windows Exes : {win_zip}") 64 | create_zip(release_files[2:4], win_zip) 65 | 66 | print("[+] Finished Creating Zip Files") 67 | 68 | 69 | if __name__ == "__main__": 70 | main() 71 | -------------------------------------------------------------------------------- /src/wasm.zig: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) Palash Bauri 3 | // 4 | // This Source Code Form is subject to the terms of the Mozilla Public 5 | // License, v. 2.0. If a copy of the MPL was not distributed with this 6 | // file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | // 8 | // SPDX-License-Identifier: MPL-2.0 9 | 10 | const std = @import("std"); 11 | const Gc = @import("gc.zig").Gc; 12 | const utils = @import("utils.zig"); 13 | const _vm = @import("vm.zig"); 14 | const Vm = _vm.Vm; 15 | const flags = @import("flags.zig"); 16 | const writer = @import("writer.zig"); 17 | 18 | extern fn writeStdout(ptr: usize, len: usize) void; 19 | extern fn writeStderr(ptr: usize, len: usize) void; 20 | 21 | fn writeOutString(bts: []const u8) void { 22 | writeStdout(@intFromPtr(bts.ptr), bts.len); 23 | } 24 | 25 | fn writeErrString(bts: []const u8) void { 26 | writeStderr(@intFromPtr(bts.ptr), bts.len); 27 | } 28 | const handyAl = std.heap.wasm_allocator; 29 | const gcAl = std.heap.wasm_allocator; 30 | 31 | export fn memAlloc(len: usize) usize { 32 | const result = handyAl.alloc(u8, len) catch return 0; 33 | return @intFromPtr(result.ptr); 34 | } 35 | 36 | export fn memFree(ptr: [*]const u8, len: usize) void { 37 | handyAl.free(ptr[0..len]); 38 | } 39 | 40 | export fn runCodeApi(rawrawSource: [*]const u8, len: u32) bool { 41 | const rawSource = rawrawSource[0..len]; 42 | 43 | var gc = Gc.new(gcAl, handyAl) catch { 44 | return false; 45 | }; 46 | 47 | const StdoutWriter = writer.OutWriter.new(writeOutString); 48 | const StderrWriter = writer.OutWriter.new(writeErrString); 49 | 50 | gc.boot(StdoutWriter.writer().any(), StderrWriter.writer().any()); 51 | const source = utils.u8tou32(rawSource, gc.hal()) catch { 52 | return false; 53 | }; 54 | 55 | var myVm = Vm.newVm(gc.hal()) catch { 56 | return false; 57 | }; 58 | 59 | myVm.bootVm(gc); 60 | 61 | const result = myVm.interpret(source); 62 | 63 | myVm.freeVm(gc.hal()); 64 | gc.hal().free(source); 65 | switch (result) { 66 | .Ok => return true, 67 | .RuntimeError => return false, 68 | .CompileError => return false, 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/value_errors.zig: -------------------------------------------------------------------------------- 1 | pub const CopyError = error{ 2 | Arr_FailedToAppendParentLink, 3 | Arr_FailedToCreateNewArray, 4 | Arr_InsertItems, 5 | Arr_ItemCopyError, 6 | Hmap_FailedToAppendParentLink, 7 | Hmap_NewHmap, 8 | Hmap_AddPair, 9 | Hmap_ItemCopyError, 10 | String_NewString, 11 | BigInt_NewBigInt, 12 | BigInt_InitInt, 13 | BigInt_AddDigit, 14 | ErrObj_NewErrObj, 15 | ErrObj_CopyError, 16 | }; 17 | 18 | pub fn copyErrorToString(e: CopyError) []const u8 { 19 | switch (e) { 20 | CopyError.Arr_FailedToAppendParentLink => { 21 | return "Failed to add the array object to parentlink"; 22 | }, 23 | CopyError.Arr_FailedToCreateNewArray => { 24 | return "Failed to create new array while copying"; 25 | }, 26 | CopyError.Arr_InsertItems => { 27 | return "Failed to insert newly copied item to new array"; 28 | }, 29 | CopyError.Arr_ItemCopyError => { 30 | return "Failed to copy array items"; 31 | }, 32 | 33 | CopyError.Hmap_FailedToAppendParentLink => { 34 | return "Failed to add the hashmap object to parentlink"; 35 | }, 36 | 37 | CopyError.Hmap_NewHmap => { 38 | return "Failed to create new hashmap while copying"; 39 | }, 40 | CopyError.Hmap_AddPair => { 41 | return "Failed to insert newly copied key,value to new hashmap"; 42 | }, 43 | CopyError.Hmap_ItemCopyError => { 44 | return "Failed to copy hashmap items"; 45 | }, 46 | 47 | CopyError.String_NewString => { 48 | return "Failed to copy string"; 49 | }, 50 | 51 | CopyError.BigInt_NewBigInt => { 52 | return "Failed to create new big integer while copying"; 53 | }, 54 | CopyError.BigInt_InitInt => { 55 | return "Failed to initialize big integer"; 56 | }, 57 | CopyError.BigInt_AddDigit => { 58 | return "Failed to copy big integer"; 59 | }, 60 | 61 | CopyError.ErrObj_CopyError, 62 | CopyError.ErrObj_NewErrObj, 63 | => { 64 | return "Failed to create copy of error object"; 65 | }, 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /web/style.css: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) Palash Bauri 3 | 4 | This Source Code Form is subject to the terms of the Mozilla Public 5 | License, v. 2.0. If a copy of the MPL was not distributed with this 6 | file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | 8 | SPDX-License-Identifier: MPL-2.0 9 | */ 10 | 11 | 12 | html { 13 | line-height: 1.5; 14 | font-size: 20px; 15 | color: #1a1a1a; 16 | background-color: white; 17 | font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif; 18 | } 19 | 20 | .container{ 21 | display: flex; 22 | border: 1px solid rgb(203 213 225); 23 | border-radius: 0.5rem; 24 | overflow: hidden; 25 | max-height: 20rem; 26 | } 27 | 28 | .container_textarea{ 29 | border: none; 30 | outline: none; 31 | padding: 0.5rem; 32 | width: 100%; 33 | font-size: 15px; 34 | } 35 | 36 | .container_lines{ 37 | border-right: 1px solid black; 38 | padding: 0.5rem; 39 | text-align: right; 40 | overflow: hidden; 41 | } 42 | 43 | .output_container { 44 | display: flex; 45 | border: 1px solid rgb(203 213 225); 46 | border-radius: 0.5rem; 47 | overflow: hidden; 48 | max-height: 20rem; 49 | } 50 | 51 | .outputbox { 52 | border: none; 53 | outline: none; 54 | padding: 0.5rem; 55 | width: 100%; 56 | min-height: 8rem; 57 | 58 | font-size: 15px; 59 | } 60 | 61 | .button_container{ 62 | display: flex; 63 | margin: 10px; 64 | flex-direction: row; 65 | justify-content: center; 66 | } 67 | 68 | .run_button{ 69 | margin: 5px 10px; 70 | padding: 15px 40px; 71 | background: #ffe488; 72 | border: 2px solid black; 73 | border-radius: 10px; 74 | 75 | font-size: 15px; 76 | font-family: monospace; 77 | font-weight: bold; 78 | 79 | } 80 | 81 | .run_button:hover{ 82 | background: white; 83 | } 84 | 85 | .clear_button{ 86 | 87 | margin: 5px 10px; 88 | padding: 15px 40px; 89 | background: whitesmoke; 90 | border: 2px solid black; 91 | border-radius: 10px; 92 | 93 | font-size: 15px; 94 | font-family: monospace; 95 | font-weight: bold; 96 | 97 | } 98 | 99 | .clear_button:hover{ 100 | background: cyan; 101 | } 102 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![Pankti Programming Language](./images/pankti_header.png) 2 | # The Pankti Programming Language 3 | 4 | 5 | ## Introduction 6 | Pankti is a dynamically typed programming language for programming in Bengali, 7 | English, Bengali phonetic as well as Combination of both. Pankti is an easy to 8 | learn programming language but it was also powerful language to create useful 9 | and fast programs. 10 | 11 | ## Why 12 | My mother tongue is Bengali. Previously there have been few attempts to build 13 | a Bengali programming language but most of them have no practical usage, so I 14 | ventured into the dark world of language design. 15 | 16 | ## Language Features 17 | ### Data Types: 18 | * Strings/স্ট্রিং: `"Hello world"`, `"pankti"`, `পলাশ বাউরি ` 19 | * Numbers/সংখ্যা: `100`, `3.14`, `1234`, `১২৩৪৫৬৭৮৯০`, `৩.১৪`, `৯9.9৯` 20 | * Dictionaries/HashMap/Map/ম্যাপ: `{"name" : "palash" , "time":7.22 , "পদবি" : "বাউরি" }` 21 | * Array/তালিকা: `["রবিবার", "Monday", 1 , 2.34]` 22 | * Booleans: `true`, `false`, `সত্যি`, `মিথ্যা` 23 | 24 | ## Variables: 25 | ```go 26 | ধরি নাম = "পলাশ" 27 | ধরি পুরোনাম = নাম + " বাউরি" 28 | ধরি মাস = "বৈশাখ" 29 | ধরি সাল = ২০২৩ 30 | ``` 31 | 32 | ## Functions: 33 | ```go 34 | কাজ ঘুমানো(নায়ক) 35 | দেখাও(নায়ক + " এখন ঘুমোচ্ছে!") 36 | শেষ 37 | ঘুমানো("পলাশ") 38 | ``` 39 | 40 | ```go 41 | Output: পলাশ এখন ঘুমোচ্ছে 42 | ``` 43 | 44 | ## Documentation 45 | * 46 | 47 | ## Project Status 48 | > Pre-alpha. Under heavy development 49 | 50 | ## Related Projects 51 | [![](https://github-readme-stats.vercel.app/api/pin/?username=bauripalash&repo=panktikhata)](https://github.com/bauripalash/panktikhata) 52 | [![](https://github-readme-stats.vercel.app/api/pin/?username=bauripalash&repo=pankti-web)](https://github.com/bauripalash/pankti-web) 53 | 54 | ## LICENSE 55 | > MPL v2 56 | 57 | >Note: Buno the Heron, the mascot is created by Me, Palash Bauri and are 58 | licensed under [Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International](https://creativecommons.org/licenses/by-nc-nd/4.0/?ref=chooser-v1) 59 | 60 | ## Special Thanks: 61 | Thorsten Ball for writing these amazing book "Writing An Interpreter In Go" and "Writing A Compiler In Go" and Robert Nystrom for writing his awesome book "Crafting Interpreters" 62 | -------------------------------------------------------------------------------- /windows/windows.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.5.33424.131 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pankti", "windows.vcxproj", "{5F8FAB4E-4D08-4044-AD6D-428C6FF56531}" 7 | EndProject 8 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "panktikhata", "panktikhata\panktikhata.vcxproj", "{23D00728-4CE2-4E49-8486-731DDBB8050F}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|x64 = Debug|x64 13 | Debug|x86 = Debug|x86 14 | Release|x64 = Release|x64 15 | Release|x86 = Release|x86 16 | EndGlobalSection 17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 18 | {5F8FAB4E-4D08-4044-AD6D-428C6FF56531}.Debug|x64.ActiveCfg = Debug|x64 19 | {5F8FAB4E-4D08-4044-AD6D-428C6FF56531}.Debug|x64.Build.0 = Debug|x64 20 | {5F8FAB4E-4D08-4044-AD6D-428C6FF56531}.Debug|x86.ActiveCfg = Debug|Win32 21 | {5F8FAB4E-4D08-4044-AD6D-428C6FF56531}.Debug|x86.Build.0 = Debug|Win32 22 | {5F8FAB4E-4D08-4044-AD6D-428C6FF56531}.Release|x64.ActiveCfg = Release|x64 23 | {5F8FAB4E-4D08-4044-AD6D-428C6FF56531}.Release|x64.Build.0 = Release|x64 24 | {5F8FAB4E-4D08-4044-AD6D-428C6FF56531}.Release|x86.ActiveCfg = Release|Win32 25 | {5F8FAB4E-4D08-4044-AD6D-428C6FF56531}.Release|x86.Build.0 = Release|Win32 26 | {23D00728-4CE2-4E49-8486-731DDBB8050F}.Debug|x64.ActiveCfg = Debug|x64 27 | {23D00728-4CE2-4E49-8486-731DDBB8050F}.Debug|x64.Build.0 = Debug|x64 28 | {23D00728-4CE2-4E49-8486-731DDBB8050F}.Debug|x86.ActiveCfg = Debug|Win32 29 | {23D00728-4CE2-4E49-8486-731DDBB8050F}.Debug|x86.Build.0 = Debug|Win32 30 | {23D00728-4CE2-4E49-8486-731DDBB8050F}.Release|x64.ActiveCfg = Release|x64 31 | {23D00728-4CE2-4E49-8486-731DDBB8050F}.Release|x64.Build.0 = Release|x64 32 | {23D00728-4CE2-4E49-8486-731DDBB8050F}.Release|x86.ActiveCfg = Release|Win32 33 | {23D00728-4CE2-4E49-8486-731DDBB8050F}.Release|x86.Build.0 = Release|Win32 34 | EndGlobalSection 35 | GlobalSection(SolutionProperties) = preSolution 36 | HideSolutionNode = FALSE 37 | EndGlobalSection 38 | GlobalSection(ExtensibilityGlobals) = postSolution 39 | SolutionGuid = {BCBB66F4-3970-4284-BCA0-6E82E8475C26} 40 | EndGlobalSection 41 | EndGlobal 42 | -------------------------------------------------------------------------------- /tests/test_stdlib_math.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from .main import run_pankti as rp 4 | 5 | import math 6 | 7 | math_abs = "stdlib_math_abs" 8 | math_pi = "stdlib_math_pi" 9 | math_e = "stdlib_math_e" 10 | math_ceil = "stdlib_math_ceil" 11 | math_cos = "stdlib_math_cos" 12 | math_sin = "stdlib_math_sin" 13 | math_tan = "stdlib_math_tan" 14 | 15 | class TestStdlibMath(unittest.TestCase): 16 | def test_math_abs(self): 17 | r = rp(math_abs).splitlines() 18 | self.assertEqual(float(r[0]) , abs(-100)) 19 | self.assertEqual(float(r[1]) , abs(11.0)) 20 | self.assertEqual(float(r[2]) , abs(99)) 21 | self.assertEqual(float(r[3]) , abs(-199.99)) 22 | self.assertEqual(float(r[4]) , abs(99.99)) 23 | 24 | def test_math_pi(self): 25 | self.assertAlmostEqual(float(rp(math_pi)) , math.pi) 26 | 27 | def test_math_e(self): 28 | self.assertAlmostEqual(float(rp(math_e)) , math.e) 29 | 30 | def test_math_ceil(self): 31 | r = rp(math_ceil).splitlines() 32 | self.assertEqual(float(r[0]) , math.ceil(1.2)) 33 | self.assertEqual(float(r[1]) , math.ceil(-99.99)) 34 | self.assertEqual(float(r[2]) , math.ceil(-1.999999999999)) 35 | self.assertEqual(float(r[3]) , math.ceil(0.1)) 36 | 37 | def test_math_cos(self): 38 | r = rp(math_cos).splitlines() 39 | self.assertAlmostEqual(float(r[0]) , math.cos(90)) 40 | self.assertAlmostEqual(float(r[1]) , math.cos(1.5708)) 41 | self.assertAlmostEqual(float(r[2]) , math.cos(1.0472)) 42 | self.assertAlmostEqual(float(r[3]) , math.cos(0.575959)) 43 | 44 | def test_math_sin(self): 45 | r = rp(math_sin).splitlines() 46 | self.assertAlmostEqual(float(r[0]) , math.sin(90)) 47 | self.assertAlmostEqual(float(r[1]) , math.sin(1.5708)) 48 | self.assertAlmostEqual(float(r[2]) , math.sin(1.0472)) 49 | self.assertAlmostEqual(float(r[3]) , math.sin(0.575959)) 50 | 51 | def test_math_tan(self): 52 | r = rp(math_tan).splitlines() 53 | self.assertAlmostEqual(float(r[0]) , math.tan(90)) 54 | self.assertAlmostEqual(float(r[1]) , math.tan(1.5708)) 55 | self.assertAlmostEqual(float(r[2]) , math.tan(1.0472)) 56 | self.assertAlmostEqual(float(r[3]) , math.tan(0.575959)) 57 | 58 | 59 | if __name__ == "__main__": 60 | unittest.main() 61 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | ZIG:=zig 2 | BUILD_DIR:=zig-out 3 | CACHE_DIR:=zig-cache 4 | TARGET:=$(BUILD_DIR)/bin/pankti 5 | SAMPLE:=a.pank 6 | DEBUGGER:=gdb 7 | WASMBIN:=zig-out/bin/pankti.wasm 8 | PYTHON:=python 9 | ICON_ICO:=images/icon.ico 10 | 11 | ifeq ($(PREFIX),) 12 | PREFIX:=/usr/local 13 | endif 14 | 15 | run: $(TARGET) 16 | @./$(TARGET) $(SAMPLE) 17 | 18 | $(TARGET): build 19 | 20 | r: $(TARGET) 21 | @./$(TARGET) $(ARGS) 22 | 23 | release: rls_setup rls_win32 rls_win64 rls_linux32 rls_linux64 24 | 25 | build: 26 | @$(ZIG) build 27 | 28 | 29 | wasm: 30 | @$(ZIG) build wasm -Dtarget=wasm32-freestanding-musl -Doptimize=ReleaseFast 31 | cp $(WASMBIN) ./web/ 32 | 33 | 34 | debug: $(TARGET) 35 | $(DEBUGGER) --args $(TARGET) $(SAMPLE) 36 | 37 | test: $(TARGET) 38 | @$(ZIG) build test 39 | @$(PYTHON) -m unittest -v 40 | 41 | 42 | rls_setup: 43 | mkdir -p dist/ 44 | 45 | rls_win32: 46 | $(ZIG) build -Dtarget=x86-windows-gnu -Doptimize=ReleaseSafe 47 | mv zig-out/bin/pankti.exe dist/pankti-win32.exe 48 | 49 | rls_win64: 50 | $(ZIG) build -Dtarget=x86_64-windows-gnu -Doptimize=ReleaseSafe 51 | mv zig-out/bin/pankti.exe dist/pankti-win64.exe 52 | 53 | rls_linux32: 54 | $(ZIG) build -Dtarget=x86-linux-gnu -Doptimize=ReleaseSafe 55 | mv zig-out/bin/pankti dist/pankti-linux32 56 | 57 | rls_linux64: 58 | $(ZIG) build -Dtarget=x86_64-linux-gnu -Doptimize=ReleaseSafe 59 | mv zig-out/bin/pankti dist/pankti-linux64 60 | 61 | resobj: 62 | $(ZIG) rc winres/pankti.rc /FO winres/pankti.res.obj 63 | 64 | perf: 65 | @echo "Building Release" 66 | $(ZIG) build -Doptimize=ReleaseFast 67 | @echo "[+] Running Perf" 68 | perf record -g -F 999 ./$(TARGET) ./sample/fib35.pank 69 | perf script -F +pid > neopank.perf 70 | @echo "[+] Finished Running Perf" 71 | 72 | 73 | install: $(TARGET) 74 | install -d $(DESTDIR)$(PREFIX)/bin 75 | install -d $(DESTDIR)$(PREFIX)/share/ 76 | install -d $(DESTDIR)$(PREFIX)/share/pankti/ 77 | install -d $(DESTDIR)$(PREFIX)/share/pankti/icons/ 78 | install -m 755 $(TARGET) $(DESTDIR)$(PREFIX)/bin 79 | install -m 644 $(ICON_ICO) $(DESTDIR)$(PREFIX)/share/pankti/icons/ 80 | 81 | uninstall: 82 | rm $(DESTDIR)$(PREFIX)/bin/pankti 83 | rm -rf $(DESTDIR)$(PREFIX)/share/pankti 84 | 85 | fmt: 86 | @find . -path ./.zig-cache -prune -o -name "*.zig"\ 87 | -exec $(ZIG) fmt {} \; 88 | 89 | clean: 90 | rm -rf $(CACHE_DIR) 91 | rm -rf $(BUILD_DIR) 92 | rm -rf ./src/ext/baurinum/.zig-cache 93 | rm -rf dist/ 94 | -------------------------------------------------------------------------------- /src/table.zig: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) Palash Bauri 3 | // 4 | // This Source Code Form is subject to the terms of the Mozilla Public 5 | // License, v. 2.0. If a copy of the MPL was not distributed with this 6 | // file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | // 8 | // SPDX-License-Identifier: MPL-2.0 9 | 10 | const std = @import("std"); 11 | const utils = @import("utils.zig"); 12 | const object = @import("object.zig"); 13 | const Vm = @import("vm.zig").Vm; 14 | const Pobj = object.PObj; 15 | const val = @import("value.zig"); 16 | const PValue = val.PValue; 17 | 18 | const MapTableContext = struct { 19 | pub fn eql(self: @This(), a: PValue, b: PValue) bool { 20 | _ = self; 21 | 22 | return a.hash() == b.hash(); 23 | } 24 | 25 | pub fn hash(self: @This(), key: PValue) u64 { 26 | _ = self; 27 | return @intCast(key.hash()); 28 | } 29 | }; 30 | 31 | pub fn MapTable() type { 32 | return std.HashMapUnmanaged( 33 | PValue, 34 | PValue, 35 | MapTableContext, 36 | std.hash_map.default_max_load_percentage, 37 | ); 38 | } 39 | 40 | const PankTableContext = struct { 41 | pub fn eql( 42 | self: @This(), 43 | a: *Pobj.OString, 44 | b: *Pobj.OString, 45 | ) bool { 46 | _ = self; 47 | //utils.printu32(a.chars, std.io.getStdOut().writer().any()); 48 | //std.debug.print("==", .{}); 49 | //utils.printu32(b.chars, std.io.getStdOut().writer().any()); 50 | //std.debug.print("\n{d}=={d}\n", .{ a.hash, b.hash }); 51 | return a.hash == b.hash; 52 | } 53 | pub fn hash(self: @This(), key: *Pobj.OString) u64 { 54 | _ = self; 55 | return @as(u64, @intCast(key.hash)); 56 | } 57 | }; 58 | 59 | pub fn PankTable() type { 60 | return std.HashMapUnmanaged( 61 | *Pobj.OString, 62 | PValue, 63 | PankTableContext, 64 | std.hash_map.default_max_load_percentage, 65 | ); 66 | } 67 | 68 | pub fn freeGlobalsTable(vm: *Vm, table: PankTable()) bool { 69 | for (table.values()) |value| { 70 | value.free(vm); 71 | } 72 | 73 | return true; 74 | } 75 | 76 | pub fn getString(self: PankTable(), hash: u32, len: usize) ?*Pobj.OString { 77 | var ite = self.iterator(); 78 | while (ite.next()) |n| { 79 | const rawStr: *Pobj.OString = n.key_ptr.*; 80 | 81 | if (rawStr.len == len and rawStr.hash == hash) { 82 | return rawStr; 83 | } 84 | } 85 | 86 | return null; 87 | } 88 | -------------------------------------------------------------------------------- /src/builtins.zig: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) Palash Bauri 3 | // 4 | // This Source Code Form is subject to the terms of the Mozilla Public 5 | // License, v. 2.0. If a copy of the MPL was not distributed with this 6 | // file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | // 8 | // SPDX-License-Identifier: MPL-2.0 9 | 10 | const std = @import("std"); 11 | const value = @import("value.zig"); 12 | const Vm = @import("vm.zig").Vm; 13 | const PValue = value.PValue; 14 | const utils = @import("utils.zig"); 15 | const valueerrors = @import("value_errors.zig"); 16 | const CopyError = valueerrors.CopyError; 17 | 18 | pub fn nCopy(vm: *Vm, argc: u8, values: []PValue) PValue { 19 | if (argc != 1) { 20 | return PValue.makeError(vm.gc, "copy(...) takes a single argument").?; 21 | } 22 | 23 | const links = vm.gc.hal().create(value.ParentLink) catch return PValue.makeNil(); 24 | links.prev = std.ArrayListUnmanaged(PValue){}; 25 | 26 | const a = values[0]; 27 | const result = a.createCopy(vm.gc, links) catch |e| { 28 | _ = links.free(vm.gc); 29 | return PValue.makeComptimeError( 30 | vm.gc, 31 | "copy(...) failed due to internal error : {s}", 32 | .{valueerrors.copyErrorToString(e)}, 33 | ).?; 34 | }; 35 | 36 | _ = links.free(vm.gc); 37 | 38 | return result; 39 | } 40 | 41 | pub fn nShow(vm: *Vm, argc: u8, values: []PValue) PValue { 42 | const links = vm.gc.hal().create( 43 | value.ParentLink, 44 | ) catch return PValue.makeNil(); 45 | 46 | links.prev = std.ArrayListUnmanaged(PValue){}; 47 | 48 | var i: usize = 0; 49 | while (i < argc) : (i += 1) { 50 | _ = values[i].printValForShow(vm.gc, links); 51 | } 52 | 53 | _ = links.free(vm.gc); 54 | 55 | return PValue.makeNil(); 56 | } 57 | 58 | pub fn nClock(vm: *Vm, argc: u8, values: []PValue) PValue { 59 | _ = vm; 60 | _ = values; 61 | _ = argc; 62 | if (utils.IS_WASM) { 63 | return PValue.makeNumber(@floatFromInt(utils.getTimestamp())); 64 | } else { 65 | const s = std.time.timestamp(); 66 | return PValue.makeNumber(@floatFromInt(s)); 67 | } 68 | } 69 | 70 | pub fn nLen(vm: *Vm, argc: u8, values: []PValue) PValue { 71 | if (argc != 1) { 72 | return PValue.makeError( 73 | vm.gc, 74 | "len(..) function only takes single argument", 75 | ).?; 76 | } 77 | 78 | if (values[0].getLen()) |len| { 79 | return PValue.makeNumber(@floatFromInt(len)); 80 | } 81 | 82 | return PValue.makeNil(); 83 | } 84 | -------------------------------------------------------------------------------- /notes/cpank/import_system.txt: -------------------------------------------------------------------------------- 1 | Pankti Internal Memo #1 2 | ======== 3 | 4 | Title: Pankti Import and Module System 5 | Author: Palash Bauri 6 | 7 | Status: Draft 8 | Created: April 10, 2023 09:23:32 IST 9 | Last Modified: April 10, 2023 10:35:30 IST 10 | 11 | ======== 12 | Abstract 13 | ======== 14 | 15 | Due to pankti programming language's dynamic nature it has been proved to be 16 | really difficult to implement a module and import system which is not only 17 | easy to implement but also efficient. Here I provide description and notes on 18 | the current prototype module/import system implemented in this C implementation 19 | of Pankti programming language 20 | 21 | ======== 22 | Description 23 | ======== 24 | 25 | The VM (struct) will hold a static array of `MODULE_MAX` (prototype : 64) 26 | number of module objects (1). It also include an integer field of module count 27 | which specified how many modules are in use currently(2); the names of modules 28 | will be hashed and stored in a array of module names which will help us fetch 29 | modules faster than comparing strings(3); The VM will also have a pointer the 30 | current module being executed(4). 31 | 32 | ``` 33 | typedef struct _Vm{ 34 | ... 35 | Module modules[MODULE_MAX]; <-----(1) 36 | int mod_count; <-----(2) 37 | uint32_t mod_names[MODULE_MAX]; <-(3) 38 | Module * current_mod; <-----(4) 39 | ... 40 | }_Vm; 41 | ``` 42 | 43 | Each Module object has a table of globals (`htable.c`)(5), A array of standard 44 | library proxy(6) and count of how many standard library are imported in this 45 | current module(7). [Discussed later; see `Standard Library`]. `FRAME_SIZE` 46 | number of call frames(8); number of frames in current module (9); module 47 | name(10); hash of the module name which gets stored in the `mod_names` field 48 | of VM(11); list of open upvalues(12); a boolean to check if the module is the 49 | default or 'genesis' module(13); a pointer to the module this module was 50 | imported from(14); the whole source code (for error reporting; Not yet 51 | implemented) (25) 52 | 53 | ``` 54 | typedef struct Module { 55 | Htable globals; <----- (5) 56 | StdProxy stdproxy[STDLIB_MAX]; <----- (6) 57 | int stdlib_count; <----- (7) 58 | CallFrame frames[FRAME_SIZE]; <----- (8) 59 | int frame_count; <----- (9) 60 | char32_t *name; <----- (10) 61 | uint32_t hash; <----- (11) 62 | ObjUpVal *open_upvs; <----- (12) 63 | bool is_default; <----- (13) 64 | struct Module *origin; <----- (14) 65 | char32_t *source_code; <----- (15) 66 | 67 | } Module; 68 | ``` 69 | -------------------------------------------------------------------------------- /src/main.zig: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) Palash Bauri 3 | // 4 | // This Source Code Form is subject to the terms of the Mozilla Public 5 | // License, v. 2.0. If a copy of the MPL was not distributed with this 6 | // file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | // 8 | // SPDX-License-Identifier: MPL-2.0 9 | 10 | const std = @import("std"); 11 | const flags = @import("flags.zig"); 12 | const run = @import("run.zig"); 13 | const builtin = @import("builtin"); 14 | const utils = @import("utils.zig"); 15 | const abouttxt = @embedFile("emfiles/about.txt"); 16 | const pankti = @import("pankti.zig"); 17 | 18 | pub fn windowsOsSetup() void { 19 | if (builtin.target.os.tag == .windows) { 20 | const win = @cImport({ 21 | @cInclude("windows.h"); 22 | }); 23 | 24 | const ioh = @cImport({ 25 | @cInclude("io.h"); 26 | }); 27 | 28 | const locale = @cImport({ 29 | @cInclude("locale.h"); 30 | }); 31 | 32 | _ = locale.setlocale(@as(c_int, 2), "bn_IN.utf8"); 33 | _ = win.SetConsoleOutputCP(@as(c_uint, @bitCast(@as(c_int, 65001)))); 34 | _ = ioh._setmode(@as(c_int, 1), @as(c_int, 131072)); 35 | } 36 | } 37 | 38 | pub fn main() !void { 39 | if (utils.IS_WASM) return; 40 | windowsOsSetup(); 41 | var gpa = std.heap.GeneralPurposeAllocator(.{}){}; 42 | const ga = gpa.allocator(); 43 | 44 | var fileToRun: ?[]u8 = null; 45 | 46 | const args = try std.process.argsAlloc(ga); 47 | 48 | if (args.len == 2) { 49 | const flag = args[1]; 50 | 51 | if (std.mem.eql( 52 | u8, 53 | flag, 54 | "-v", 55 | ) or std.mem.eql( 56 | u8, 57 | flag, 58 | "--version", 59 | )) { 60 | std.debug.print("{s}\n", .{pankti.build_options.version_string}); 61 | } else if (std.mem.eql(u8, flag, "-h") or std.mem.eql( 62 | u8, 63 | flag, 64 | "--help", 65 | )) { 66 | std.debug.print(abouttxt, .{pankti.build_options.version_string}); 67 | } else { 68 | fileToRun = try ga.alloc(u8, args[1].len); 69 | @memcpy(fileToRun.?, args[1]); 70 | } 71 | } else if (args.len == 1) { 72 | std.debug.print(abouttxt, .{pankti.build_options.version_string}); 73 | std.process.exit(0); 74 | } 75 | std.process.argsFree(ga, args); 76 | 77 | defer { 78 | if (fileToRun) |f| { 79 | ga.free(f); 80 | } 81 | _ = gpa.deinit(); 82 | } 83 | 84 | if (fileToRun) |f| { 85 | const isOk = run.runFile(f); 86 | if (!isOk) { 87 | std.process.exit(1); 88 | } 89 | } 90 | } 91 | 92 | test "AllTest" { 93 | std.testing.refAllDecls(@This()); 94 | _ = @import("lexer/lexer.zig"); 95 | _ = @import("instruction.zig"); 96 | _ = @import("vm.zig"); 97 | _ = @import("compiler.zig"); 98 | } 99 | -------------------------------------------------------------------------------- /windows/windows.rc: -------------------------------------------------------------------------------- 1 | // Microsoft Visual C++ generated resource script. 2 | // 3 | #include "resource.h" 4 | 5 | #define APSTUDIO_READONLY_SYMBOLS 6 | ///////////////////////////////////////////////////////////////////////////// 7 | // 8 | // Generated from the TEXTINCLUDE 2 resource. 9 | // 10 | #include "winres.h" 11 | 12 | ///////////////////////////////////////////////////////////////////////////// 13 | #undef APSTUDIO_READONLY_SYMBOLS 14 | 15 | ///////////////////////////////////////////////////////////////////////////// 16 | // English (United States) resources 17 | 18 | #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) 19 | LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US 20 | #pragma code_page(1252) 21 | 22 | #ifdef APSTUDIO_INVOKED 23 | ///////////////////////////////////////////////////////////////////////////// 24 | // 25 | // TEXTINCLUDE 26 | // 27 | 28 | 1 TEXTINCLUDE 29 | BEGIN 30 | "resource.h\0" 31 | END 32 | 33 | 2 TEXTINCLUDE 34 | BEGIN 35 | "#include ""winres.h""\r\n" 36 | "\0" 37 | END 38 | 39 | 3 TEXTINCLUDE 40 | BEGIN 41 | "\r\n" 42 | "\0" 43 | END 44 | 45 | #endif // APSTUDIO_INVOKED 46 | 47 | 48 | ///////////////////////////////////////////////////////////////////////////// 49 | // 50 | // Version 51 | // 52 | 53 | VS_VERSION_INFO VERSIONINFO 54 | FILEVERSION 0,4,0,0 55 | PRODUCTVERSION 0,4,0,0 56 | FILEFLAGSMASK 0x3fL 57 | #ifdef _DEBUG 58 | FILEFLAGS 0x1L 59 | #else 60 | FILEFLAGS 0x0L 61 | #endif 62 | FILEOS 0x40004L 63 | FILETYPE 0x1L 64 | FILESUBTYPE 0x0L 65 | BEGIN 66 | BLOCK "StringFileInfo" 67 | BEGIN 68 | BLOCK "040904b0" 69 | BEGIN 70 | VALUE "CompanyName", "Palash Bauri" 71 | VALUE "FileDescription", "Pankti Programming Language" 72 | VALUE "FileVersion", "0.4.0.0" 73 | VALUE "InternalName", "pankti.exe" 74 | VALUE "LegalCopyright", "Copyright (C) Palash Bauri" 75 | VALUE "OriginalFilename", "pankti.exe" 76 | VALUE "ProductName", "Pankti" 77 | VALUE "ProductVersion", "0.4.0.0" 78 | END 79 | END 80 | BLOCK "VarFileInfo" 81 | BEGIN 82 | VALUE "Translation", 0x409, 1200 83 | END 84 | END 85 | 86 | 87 | ///////////////////////////////////////////////////////////////////////////// 88 | // 89 | // Icon 90 | // 91 | 92 | // Icon with lowest ID value placed first to ensure application icon 93 | // remains consistent on all systems. 94 | IDI_ICON1 ICON "icon.ico" 95 | 96 | #endif // English (United States) resources 97 | ///////////////////////////////////////////////////////////////////////////// 98 | 99 | 100 | 101 | #ifndef APSTUDIO_INVOKED 102 | ///////////////////////////////////////////////////////////////////////////// 103 | // 104 | // Generated from the TEXTINCLUDE 3 resource. 105 | // 106 | 107 | 108 | ///////////////////////////////////////////////////////////////////////////// 109 | #endif // not APSTUDIO_INVOKED 110 | 111 | -------------------------------------------------------------------------------- /src/lexer/keywords.zig: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) Palash Bauri 3 | // 4 | // This Source Code Form is subject to the terms of the Mozilla Public 5 | // License, v. 2.0. If a copy of the MPL was not distributed with this 6 | // file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | // 8 | // SPDX-License-Identifier: MPL-2.0 9 | 10 | pub const K_EN_LET: []const u8 = "let"; 11 | pub const K_EN_SHOW: []const u8 = "show"; 12 | pub const K_EN_AND: []const u8 = "and"; 13 | pub const K_EN_OR: []const u8 = "or"; 14 | pub const K_EN_END: []const u8 = "end"; 15 | pub const K_EN_IF: []const u8 = "if"; 16 | pub const K_EN_THEN: []const u8 = "then"; 17 | pub const K_EN_ELSE: []const u8 = "else"; 18 | pub const K_EN_WHILE: []const u8 = "while"; 19 | pub const K_EN_NIL: []const u8 = "nil"; 20 | pub const K_EN_TRUE: []const u8 = "true"; 21 | pub const K_EN_FALSE: []const u8 = "false"; 22 | pub const K_EN_RETURN: []const u8 = "return"; 23 | pub const K_EN_FUNC: []const u8 = "func"; 24 | pub const K_EN_IMPORT: []const u8 = "import"; 25 | pub const K_EN_PANIC: []const u8 = "panic"; 26 | pub const K_EN_DO: []const u8 = "do"; 27 | pub const K_EN_BREAK: []const u8 = "break"; 28 | pub const K_EN_LEN: []const u8 = "len"; 29 | pub const K_EN_CLOCK: []const u8 = "clock"; 30 | 31 | pub const K_BN_LET: []const u8 = "ধরি"; 32 | pub const K_BN_SHOW: []const u8 = "দেখাও"; 33 | pub const K_BN_AND: []const u8 = "এবং"; 34 | pub const K_BN_OR: []const u8 = "বা"; 35 | pub const K_BN_END: []const u8 = "শেষ"; 36 | pub const K_BN_IF: []const u8 = "যদি"; 37 | pub const K_BN_THEN: []const u8 = "তাহলে"; 38 | pub const K_BN_ELSE: []const u8 = "নাহলে"; 39 | pub const K_BN_WHILE: []const u8 = "যতক্ষণ"; 40 | pub const K_BN_NIL: []const u8 = "নিল"; 41 | pub const K_BN_TRUE: []const u8 = "সত্যি"; 42 | pub const K_BN_FALSE: []const u8 = "মিথ্যা"; 43 | pub const K_BN_RETURN: []const u8 = "ফেরাও"; 44 | pub const K_BN_FUNC: []const u8 = "কাজ"; 45 | pub const K_BN_IMPORT: []const u8 = "আনয়ন"; 46 | pub const K_BN_PANIC: []const u8 = "প্যানিক"; 47 | pub const K_BN_DO: []const u8 = "করো"; 48 | pub const K_BN_BREAK: []const u8 = "ভাঙো"; 49 | pub const K_BN_LEN: []const u8 = "আয়তন"; 50 | pub const K_BN_CLOCK: []const u8 = "সময়"; 51 | 52 | pub const K_PN_LET: []const u8 = "dhori"; 53 | pub const K_PN_SHOW: []const u8 = "dekhau"; 54 | pub const K_PN_AND: []const u8 = "ebong"; 55 | pub const K_PN_OR: []const u8 = "ba"; 56 | pub const K_PN_END: []const u8 = "sesh"; 57 | pub const K_PN_IF: []const u8 = "jodi"; 58 | pub const K_PN_THEN: []const u8 = "tahole"; 59 | pub const K_PN_ELSE: []const u8 = "nahole"; 60 | pub const K_PN_WHILE: []const u8 = "jotokhon"; 61 | pub const K_PN_NIL: []const u8 = K_EN_NIL; 62 | pub const K_PN_TRUE: []const u8 = "sotti"; 63 | pub const K_PN_FALSE: []const u8 = "mittha"; 64 | pub const K_PN_RETURN: []const u8 = "ferau"; 65 | pub const K_PN_FUNC: []const u8 = "kaj"; 66 | pub const K_PN_IMPORT: []const u8 = "anoyon"; 67 | pub const K_PN_PANIC: []const u8 = K_EN_PANIC; 68 | pub const K_PN_DO: []const u8 = "koro"; 69 | pub const K_PN_BREAK: []const u8 = "bhango"; 70 | pub const K_PN_LEN: []const u8 = "ayoton"; 71 | pub const K_PN_CLOCK: []const u8 = "somoy"; 72 | -------------------------------------------------------------------------------- /src/stack.zig: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) Palash Bauri 3 | // 4 | // This Source Code Form is subject to the terms of the Mozilla Public 5 | // License, v. 2.0. If a copy of the MPL was not distributed with this 6 | // file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | // 8 | // SPDX-License-Identifier: MPL-2.0 9 | 10 | const std = @import("std"); 11 | const PValue = @import("value.zig").PValue; 12 | const PObj = @import("object.zig").PObj; 13 | const ins = @import("instruction.zig"); 14 | const table = @import("table.zig"); 15 | 16 | const FRAME_MAX = 64; 17 | const STACK_MAX = FRAME_MAX * std.math.maxInt(u8); 18 | 19 | pub const StackError = error{ 20 | StackOverflow, 21 | StackUnderflow, 22 | StackFailPush, 23 | }; 24 | 25 | pub const VStack = struct { 26 | stack: [STACK_MAX]PValue, 27 | head: [*]PValue, 28 | top: [*]PValue, 29 | count: usize, 30 | 31 | const Self = @This(); 32 | 33 | pub fn presentcount(self: *Self) u64 { 34 | return (@as( 35 | u64, 36 | @intCast(@intFromPtr(self.top)), 37 | ) - @as( 38 | u64, 39 | @intCast(@intFromPtr(self.head)), 40 | )) / @sizeOf(*PValue); 41 | } 42 | 43 | pub fn clear(self: *Self) StackError!void { 44 | while (self.presentcount() != 0) { 45 | _ = try self.pop(); 46 | } 47 | } 48 | 49 | pub fn push(self: *Self, value: PValue) StackError!void { 50 | if (self.presentcount() >= STACK_MAX) { 51 | return StackError.StackOverflow; 52 | } 53 | self.top[0] = value; 54 | self.top += 1; 55 | self.count += 1; 56 | } 57 | 58 | pub fn pop(self: *Self) StackError!PValue { 59 | if (self.presentcount() == 0) { 60 | return StackError.StackUnderflow; 61 | } 62 | self.top -= 1; 63 | self.count -= 1; 64 | return self.top[0]; 65 | } 66 | }; 67 | 68 | pub const CallFrame = struct { 69 | closure: *PObj.OClosure, 70 | ip: [*]u8, 71 | slots: [*]PValue, 72 | globals: *table.PankTable(), 73 | globOwner: u32, 74 | 75 | const Self = @This(); 76 | 77 | pub inline fn readByte(self: *Self) ins.OpCode { 78 | const bt: ins.OpCode = @enumFromInt(self.ip[0]); 79 | 80 | self.ip += 1; 81 | 82 | return bt; 83 | } 84 | 85 | pub inline fn readU16(self: *Self) u16 { 86 | const b1 = self.readRawByte(); 87 | const b2 = self.readRawByte(); 88 | 89 | return (@as(u16, @intCast(b1)) << 8) | @as(u16, @intCast(b2)); 90 | } 91 | 92 | pub inline fn readRawByte(self: *Self) u8 { 93 | const bt = self.ip[0]; 94 | 95 | self.ip += 1; 96 | 97 | return bt; 98 | } 99 | 100 | pub inline fn readConst(self: *Self) PValue { 101 | return self.closure.function.ins.cons.items[self.readRawByte()]; 102 | //return self.ins.cons.items[self.readRawByte()]; 103 | } 104 | 105 | pub inline fn readStringConst(self: *Self) *PObj.OString { 106 | return self.readConst().asObj().asString(); 107 | } 108 | }; 109 | 110 | pub const CallStack = struct { 111 | stack: [FRAME_MAX]CallFrame, 112 | count: u32 = 0, 113 | }; 114 | -------------------------------------------------------------------------------- /src/compiler_errors.zig: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) Palash Bauri 3 | // 4 | // This Source Code Form is subject to the terms of the Mozilla Public 5 | // License, v. 2.0. If a copy of the MPL was not distributed with this 6 | // file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | // 8 | // SPDX-License-Identifier: MPL-2.0 9 | 10 | pub const MORE_THAN_255_ARGS = "২৫৫টির বেশি আর্গুমেন্ট দেওয়া হয়েছে। "; 11 | pub const EXPECT_RPAREN_AFTER_LIST = "আর্গুমেন্ট তালিকার পর একটি ')' পাওয়া উচিত ছিল। "; 12 | pub const EXPECTED_MOD_NAME = "এখানে মডিউলটির নাম পাওয়া উচিত ছিল।"; 13 | pub const EXPECTED_FUNC_NAME = "এখানে কাজ/ ফাংশনের নাম পাওয়া উচিত ছিল"; 14 | pub const EXPECTED_LPAREN_AFTER_FUNCTION_NAME = "কাজের নামের পর একটি '(' উচিত ছিল"; 15 | pub const TOO_MANY_CLOSURE_VARS = "অনেক বেশি ক্লোজার চলরাশি প্রাপ্ত হয়েছে"; 16 | pub const TOO_MANY_LOCAL_VARS = "অনেক বেশি স্থানীয় চলরাশি প্রাপ্ত হয়েছে"; 17 | pub const LOCAL_VAR_OWN_INIT = "স্থানীয় চলরাশি নিজের তৈরির সময় নিজের মান পড়তে পারবে না"; 18 | pub const EXPECTED_PARAM_NAME = "এখানে ফাংশনের আর্গুমেন্টের নাম পাওয়া উচিত ছিল"; 19 | pub const EXPECT_RPAREN_AFTER_PARAM_LIST = "ফাংশনের আর্গুমেন্ট নামের তালিকার পর একটি ')' পাওয়া উচিত ছিল। "; 20 | pub const TOO_MANY_MAP_ITEMS = "অনেক অনেক বেশি ম্যাপের রাশি দেওয়া হয়েছে"; 21 | pub const EXPECTED_COLON_AFTER_MAP_KEY = "ম্যাপের সূচকের পরে একটি ':' পাওয়া উচিত ছিল"; 22 | pub const EXPECTED_CURLY_R_BRACKET_AFTER_MAP = "ম্যাপের রাশিগুলোর একেবারে শেষে একটি '}' পাওয়া উচিত ছিল"; 23 | pub const EXPECTED_CURLY_R_BRACKET_AFTER_BLOCKS = "কোড ব্লকের শেষে একটি '}' পাওয়া উচিত ছিল"; 24 | pub const TOO_MANY_ITEMS_IN_ARRAY = "তালিকাতে অনেক বেশি রাশি দেওয়া হয়েছে"; 25 | pub const EXPECTED_S_BRACKET_R_AFTER_ARRAY = "তালিকার রাশিগুলির শেষে একটি ']' পাওয়া উচিত ছিল"; 26 | pub const EXPECTED_S_BRAC_R_AFTER_ARR_INDEX = "তালিকার সূচকীয় রাশির শেষে একটি ']' পাওয়া উচিত ছিল"; 27 | pub const EXPECTED_RPAREN_AFTER_GROUP = "গ্রুপ কোডের পর শেষে একটি ')' পাওয়া উচিত ছিল"; 28 | pub const ATE_SEMICOLON = "অপ্রয়োজনীয় সেমিকোলন"; 29 | pub const RETURN_FROM_SCRIPT = "প্রধান স্ক্রিপ্ট থেকে কিছু ফেরানো যাবে না"; 30 | pub const EXPECTED_IMPORT_NAME = "আনয়নের নাম পাওয়া উচিত ছিল"; 31 | pub const FAILED_PARSE_EXPRESSION = "এক্সপ্রেশন পড়া সম্ভব হল না"; 32 | pub const EXPECTED_VAR_NAME = "এখানে চলরাশির নাম পাওয়া উচিত ছিল"; 33 | pub const VAR_ALREADY_EXISTS = "এই নামের চলরাশি আগের থেকেই বর্তমান"; 34 | pub const EXPECTED_END = "এখানে একটি 'শেষ' পাওয়া উচিত ছিল"; 35 | pub const EXPECTED_THEN = "'যদি'-র পর 'তাহলে' পাওয়া উচিত ছিল"; 36 | pub const EXPECTED_END_AFTER_IF_WITH_NO_ELSE = "'যদি' এক্সপ্রেশনের পর যদি 'নাহলে' না থাকে তাহলে একটি 'শেষ' পাওয়া উচিত ছিল"; 37 | pub const EXPECTED_DO_AFTER_WHILE = "'যতক্ষণ' এর পরে 'করো' পাওয়া উচিত ছিল"; 38 | pub const LOOP_TOO_BIG = "লুপটি অতিরিক্ত বড়"; 39 | pub const LOOP_JUMP_TOO_BIG = "লুপের ভেতর অনেক কোড থাকায় কাজ করতে সফল হওয়া গেল না"; 40 | pub const EXPECTED_EXPR = "এখানে একটি এক্সপ্রেশন পাওয়া উচিত ছিল"; 41 | pub const NO_INFIX_RULE = "সম্ভবত অভ্যন্তরীণ গোলযোগ। এই জিনিস নিয়ে করা উচিত জানা নেই"; 42 | pub const INVALID_ASSIGN = "এই রাশিকে চল রাশির মতো ব্যবহার করা সম্ভব নয়"; 43 | pub const ERR = "গোলযোগ"; 44 | pub const ERR_AT_END = "একেবারে শেষে"; 45 | pub const ERR_AT = "এখানে"; 46 | pub const NONG_LINE = "নং লাইনে"; 47 | pub const STRING_COMP_MEMORY_ALOC = "স্ট্রিং পড়ার সময় সাময়িক স্ট্রিং তৈরি করা গেল না"; 48 | pub const STRING_INVALID_CP = "স্ট্রিং পড়া গেল না, অবৈধ ইউনিকোড বিন্যাসক্রম"; 49 | pub const STRING_U4_NOT_4 = "স্ট্রিং পড়া গেল না, অবৈধ ইউনিকোড বিন্যাসক্রম, মোট চারটি অক্ষর পাওয়া উচিত ছিল"; 50 | pub const STRING_U8_NOT_8 = "স্ট্রিং পড়া গেল না, অবৈধ ইউনিকোড বিন্যাসক্রম, মোট আটটি অক্ষর পাওয়া উচিত ছিল"; 51 | pub const STRING_TEMP_APPEND = "স্ট্রিং পড়া গেল না, অপর্যাপ্ত মেমরি বর্তমান"; 52 | pub const STRING_COMPILE_FAIL = "স্ট্রিং পড়া গেল না। "; 53 | pub const STRING_INVALID_ESCAPE = "স্ট্রিং পড়া গেল না, অবৈধ 'এস্কেপ' বিন্যাসক্রম"; 54 | -------------------------------------------------------------------------------- /src/stdlib/map.zig: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) Palash Bauri 3 | // 4 | // This Source Code Form is subject to the terms of the Mozilla Public 5 | // License, v. 2.0. If a copy of the MPL was not distributed with this 6 | // file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | // 8 | // SPDX-License-Identifier: MPL-2.0 9 | 10 | const std = @import("std"); 11 | const value = @import("../value.zig"); 12 | const Vm = @import("../vm.zig").Vm; 13 | const PValue = value.PValue; 14 | const utils = @import("../utils.zig"); 15 | const stdlib = @import("stdlib.zig"); 16 | const PObj = @import("../object.zig").PObj; 17 | 18 | //ম্যাপ 19 | pub const Name: []const u8 = "ম্যাপ"; 20 | 21 | pub const NameFuncExists: []const u8 = "বর্তমান"; 22 | pub fn map_Exists(vm: *Vm, argc: u8, values: []PValue) PValue { 23 | if (argc != 2) { 24 | return PValue.makeError(vm.gc, "বর্তমান(ম্যাপ, সূচক) কাজটি মাত্র দুটি চলরাশি গ্রহণ করে").?; 25 | } 26 | 27 | if (!values[0].isObj()) { 28 | return PValue.makeError(vm.gc, "বর্তমান(ম্যাপ, সূচক) কাজটির প্রথম চলরাশিটি একটি ম্যাপ হতে হবে").?; 29 | } 30 | 31 | if (!values[0].asObj().isHmap()) { 32 | return PValue.makeError(vm.gc, "বর্তমান(ম্যাপ, সূচক) কাজটির প্রথম চলরাশিটি একটি ম্যাপ হতে হবে").?; 33 | } 34 | 35 | const rawMap = values[0].asObj().asHmap(); 36 | 37 | if (rawMap.values.getKey(values[1])) |_| { 38 | return PValue.makeBool(true); 39 | } else { 40 | return PValue.makeBool(false); 41 | } 42 | } 43 | pub const NameFuncKeys: []const u8 = "সূচক"; 44 | pub fn map_Keys(vm: *Vm, argc: u8, values: []PValue) PValue { 45 | if (argc != 1) { 46 | return PValue.makeError(vm.gc, "সূচক(ম্যাপ) কাজটি মাত্র একটি চলরাশি গ্রহণ করে।").?; 47 | } 48 | 49 | if (!values[0].isObj()) { 50 | return PValue.makeError(vm.gc, "সূচক(ম্যাপ) কাজটিতে প্রদত্ত চলরাশি ম্যাপ হতে হবে").?; 51 | } 52 | 53 | if (!values[0].asObj().isHmap()) { 54 | return PValue.makeError(vm.gc, "সূচক(ম্যাপ) কাজটিতে প্রদত্ত চলরাশি ম্যাপ হতে হবে").?; 55 | } 56 | 57 | const rawMap = values[0].asObj().asHmap(); 58 | 59 | var objArr = vm.gc.newObj(PObj.OType.Ot_Array, PObj.OArray) catch { 60 | return PValue.makeNil(); 61 | }; 62 | 63 | objArr.init(); 64 | 65 | vm.stack.push(PValue.makeObj(objArr.parent())) catch { 66 | return PValue.makeNil(); 67 | }; 68 | 69 | var ite = rawMap.values.keyIterator(); 70 | 71 | while (ite.next()) |key| { 72 | if (!objArr.addItem(vm.gc, key.*)) return PValue.makeNil(); 73 | } 74 | 75 | return vm.stack.pop() catch return PValue.makeNil(); 76 | } 77 | 78 | pub const NameFuncValues: []const u8 = "মান"; 79 | pub fn map_Values(vm: *Vm, argc: u8, values: []PValue) PValue { 80 | if (argc != 1) { 81 | return PValue.makeError(vm.gc, "মান(ম্যাপ) কাজটি মাত্র একটি চলরাশি গ্রহণ করে।").?; 82 | } 83 | 84 | if (!values[0].isObj()) { 85 | return PValue.makeError(vm.gc, "মান(ম্যাপ) কাজটিতে প্রদত্ত চলরাশি ম্যাপ হতে হবে").?; 86 | } 87 | 88 | if (!values[0].asObj().isHmap()) { 89 | return PValue.makeError(vm.gc, "মান(ম্যাপ) কাজটিতে প্রদত্ত চলরাশি ম্যাপ হতে হবে").?; 90 | } 91 | const rawMap = values[0].asObj().asHmap(); 92 | 93 | var objArr = vm.gc.newObj(PObj.OType.Ot_Array, PObj.OArray) catch { 94 | return PValue.makeNil(); 95 | }; 96 | 97 | objArr.init(); 98 | 99 | vm.stack.push(PValue.makeObj(objArr.parent())) catch { 100 | return PValue.makeNil(); 101 | }; 102 | 103 | var ite = rawMap.values.valueIterator(); 104 | 105 | while (ite.next()) |val| { 106 | if (!objArr.addItem(vm.gc, val.*)) return PValue.makeNil(); 107 | } 108 | 109 | return vm.stack.pop() catch return PValue.makeNil(); 110 | } 111 | -------------------------------------------------------------------------------- /notes/cpank/old/import_system.txt: -------------------------------------------------------------------------------- 1 | # Import System 2 | 3 | I am not really sure how to implement the import system. So here are some 4 | ideas. 5 | 6 | Global table VM can be a table of table -> 7 | 8 | 9 | +-------------------+------------+------+------------------+ 10 | |Glob Table Name -> | __default | math | os | 11 | +-------------------+------------+------+------------------+ 12 | |Hash Key -> | 0000 | 0001 | 0002 | 13 | +-------------------+------------+------+------------------+ 14 | | | | | | 15 | +-------------------+------------+------+------------------+ 16 | |Key |hello() |pi() | read_file(...) | 17 | +-------------------+------------+------+------------------+ 18 | |Value |return 3.14 |a^b | (native) fopen...| 19 | +-------------------+------------+------+------------------+ 20 | 21 | 22 | Here default is the main module which is importing 'math' and 'os', 23 | __default should access math or os functions with syntax like this -> 24 | 25 | math.pi() or .pi() 26 | os.read_file("a.foo") or .read_file("a.foo") 27 | 28 | 29 | 30 | 31 | math nor os should be able to access or mutate anything of the importer. 32 | 33 | //file -> my_math.pank 34 | _______________ 35 | │ │ │ 36 | │1│fun pi() │ 37 | │2│ return 3.14;│ 38 | │3│end │ 39 | │_│_____________│ 40 | 41 | 42 | //file -> a.pank 43 | ___________________________ 44 | │ │ │ 45 | │1│import m "my_math.pank" │ 46 | │2│let my_pi = 3.1; │ 47 | │3│let pi = m.pi(); │ 48 | │4│ │ 49 | │5│show my_pi; //prints 3.1 │ 50 | │6│show pi; //prints 3.14 │ 51 | │_│_________________________│ 52 | 53 | 54 | here everything is good. my_math.pank doesn't try to mutate anything from 55 | __default aka. its importer. 56 | 57 | but somehow if any malicious party modifies the my_math.pank file like this 58 | 59 | ___________________ 60 | │ │ │ 61 | │1│ fun pi() │ 62 | │2│ my_pi = 2; │ 63 | │3│ return 3.14;│ 64 | │4│ end │ 65 | │_│_________________│ 66 | 67 | 68 | this should create a error. But theoretically importer can mutate items from 69 | import. As a result, this is theoretically valid from __default: 70 | 71 | _____________________________ 72 | │ │ │ 73 | │1 │ │ 74 | │2 │import m "my_math.pank" │ 75 | │3 │ │ 76 | │4 │fun new_pi() │ 77 | │5 │ return 3 │ 78 | │6 │end │ 79 | │7 │ │ 80 | │8 │show m.pi() //prints 3.14 │ 81 | │9 │ │ 82 | │10│m.pi = new_pi; │ 83 | │11│ │ 84 | │12│show m.pi() //prints 3 │ 85 | │__│__________________________│ 86 | 87 | 88 | ------------------------------------------------------------------------------- 89 | 90 | I am thinking what if every file was a module struct with its own global table 91 | which gets pushed into the global pool (global table of table). 92 | 93 | 94 | Global Pool 95 | +-__default table 96 | +- 97 | +-math table 98 | | `- 99 | | `-pi() -> return 3.14; 100 | +-my_math table 101 | | `- 102 | | `-bad_pi() -> my_pi = 2; return 3.14; 103 | `-os 104 | 105 | 106 | when in __default , if we call my_math.bad_pi() 107 | 108 | my_math . bad_pi() 109 | ^^^^^^^ 110 | 111 | we look for bad_pi() function in `my_math` global table. 112 | 113 | when we are running my_math. 114 | `my_math` becomes temporary __default, and previous __default (importer) 115 | doesn't exist in my_math's prespective, then when try to set my_pi variable 116 | we look for in __default table (which is actually just my_math's temporary 117 | table). This way bad_pi() creates error as the variable 'my_pi' doesn't exist 118 | in its global table. 119 | 120 | We can even give each call frame it's own global table, that way it will still be able go up till it's parent global pool to look up variables. 121 | 122 | Each file will be a module and have a global poll of it's own, like __default for the main one 123 | 124 | But what happens when we pass a variable to a imported function. how will it 125 | access it. we need to somehow create a link between importer supplied variable 126 | and import's global table to look for local variable in function scope ??? 127 | -------------------------------------------------------------------------------- /src/run.zig: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) Palash Bauri 3 | // 4 | // This Source Code Form is subject to the terms of the Mozilla Public 5 | // License, v. 2.0. If a copy of the MPL was not distributed with this 6 | // file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | // 8 | // SPDX-License-Identifier: MPL-2.0 9 | 10 | const std = @import("std"); 11 | const Gc = @import("gc.zig").Gc; 12 | const utils = @import("utils.zig"); 13 | const _vm = @import("vm.zig"); 14 | const Vm = _vm.Vm; 15 | const IntrpResult = _vm.IntrpResult; 16 | const flags = @import("flags.zig"); 17 | const writer = @import("writer.zig"); 18 | 19 | const openfile = @import("openfile.zig").openfile; 20 | 21 | fn _run(rawSource: []const u8, gc: *Gc) bool { 22 | //const source = utils.u8tou32(rawSource, gc.hal()) catch |e| { 23 | // std.debug.print( 24 | // "Failed to convert UTF-8 encoded source to UTF-32 encoded text : {any}\n", 25 | // .{e}, 26 | // ); 27 | // return false; 28 | //}; 29 | 30 | var myVm = Vm.newVm(gc.hal()) catch { 31 | std.debug.print("Failed to create a Vm\n", .{}); 32 | return false; 33 | }; 34 | 35 | myVm.bootVm(gc); 36 | 37 | const result = myVm.interpret(rawSource); 38 | 39 | myVm.freeVm(gc.hal()); 40 | //gc.hal().free(source); 41 | if (flags.DEBUG_FINAL) { 42 | std.debug.print("VM RESULT -> {s}\n", .{result.toString()}); 43 | } 44 | switch (result) { 45 | .Ok => return true, 46 | .RuntimeError => return false, 47 | .CompileError => return false, 48 | } 49 | } 50 | 51 | pub fn runCode16(rawSource: []const u16) bool { 52 | var handyGpa = std.heap.GeneralPurposeAllocator(.{}){}; 53 | var gcGpa = std.heap.GeneralPurposeAllocator(.{}){}; 54 | 55 | const handyAl = handyGpa.allocator(); 56 | const gcAl = gcGpa.allocator(); 57 | 58 | var gc = Gc.new(gcAl, handyAl) catch { 59 | std.debug.print("Failed to create a Garbage Collector\n", .{}); 60 | return false; 61 | }; 62 | 63 | var a = [0]u8{}; 64 | var stdWriter = std.fs.File.stdout().writer(&a); 65 | var sterrWriter = std.fs.File.stderr().writer(&a); 66 | gc.boot(&stdWriter, &sterrWriter); 67 | 68 | const source: []u8 = std.unicode.utf16leToUtf8Alloc( 69 | gc.hal(), 70 | rawSource, 71 | ) catch { 72 | std.debug.print("Failed encode source code as UTF-16", .{}); 73 | return false; 74 | }; 75 | 76 | defer { 77 | gc.hal().free(source); 78 | gc.freeGc(gcAl); 79 | _ = handyGpa.deinit(); 80 | _ = gcGpa.deinit(); 81 | } 82 | 83 | return _run(source, gc); 84 | } 85 | 86 | pub fn runCode(source: []const u8) bool { 87 | var handyGpa = std.heap.GeneralPurposeAllocator(.{}){}; 88 | var gcGpa = std.heap.GeneralPurposeAllocator(.{}){}; 89 | 90 | const handyAl = handyGpa.allocator(); 91 | const gcAl = gcGpa.allocator(); 92 | 93 | var gc = Gc.new(gcAl, handyAl) catch { 94 | std.debug.print("Failed to create a Garbage Collector\n", .{}); 95 | return false; 96 | }; 97 | 98 | gc.boot(std.io.getStdOut().writer(), std.io.getStdErr().writer()); 99 | 100 | defer { 101 | gc.freeGc(gcAl); 102 | _ = handyGpa.deinit(); 103 | _ = gcGpa.deinit(); 104 | } 105 | 106 | return _run(source, gc); 107 | } 108 | 109 | pub fn runFile(filepath: []const u8) bool { 110 | var handyGpa = std.heap.GeneralPurposeAllocator(.{}){}; 111 | var gcGpa = std.heap.GeneralPurposeAllocator(.{}){}; 112 | 113 | const handyAl = handyGpa.allocator(); 114 | const gcAl = gcGpa.allocator(); 115 | 116 | var gc = Gc.new(gcAl, handyAl) catch { 117 | std.debug.print("Failed to create a Garbage Collector\n", .{}); 118 | return false; 119 | }; 120 | 121 | //var a = std.ArrayList(u8).init(gc.hal()); 122 | 123 | var a = [0]u8{}; 124 | var stdWriter = std.fs.File.stdout().writer(&a); 125 | var sterrWriter = std.fs.File.stderr().writer(&a); 126 | gc.boot(&stdWriter, &sterrWriter); 127 | //gc.boot(a.writer().any(), a.writer().any()); 128 | 129 | const rawSource: []u8 = openfile(filepath, gc.hal()) catch { 130 | std.debug.print("[X] Failed to open file '{s}'", .{filepath}); 131 | return false; 132 | }; 133 | 134 | defer { 135 | gc.hal().free(rawSource); 136 | //a.deinit(); 137 | gc.freeGc(gcAl); 138 | 139 | _ = handyGpa.deinit(); 140 | _ = gcGpa.deinit(); 141 | } 142 | const result = _run(rawSource, gc); 143 | 144 | //std.debug.print("{any}", .{a.items}); 145 | 146 | return result; 147 | } 148 | -------------------------------------------------------------------------------- /src/stdlib/os.zig: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) Palash Bauri 3 | // 4 | // This Source Code Form is subject to the terms of the Mozilla Public 5 | // License, v. 2.0. If a copy of the MPL was not distributed with this 6 | // file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | // 8 | // SPDX-License-Identifier: MPL-2.0 9 | 10 | const std = @import("std"); 11 | const value = @import("../value.zig"); 12 | const Vm = @import("../vm.zig").Vm; 13 | const PValue = value.PValue; 14 | const utils = @import("../utils.zig"); 15 | const stdlib = @import("stdlib.zig"); 16 | const msl = stdlib.msl; 17 | const builtin = @import("builtin"); 18 | const errs = @import("os_errors.zig"); 19 | 20 | //ওএস 21 | pub const Name = "ওএস"; 22 | // নাম 23 | pub const NameFuncName = "নাম"; 24 | pub fn os_Name(vm: *Vm, argc: u8, values: []PValue) PValue { 25 | _ = values; 26 | if (argc != 0) { 27 | return PValue.makeComptimeError( 28 | vm.gc, 29 | errs.OS_NAME_ARG_NOT_ZERO, 30 | .{argc}, 31 | ).?; 32 | } 33 | const nm = switch (builtin.target.os.tag) { 34 | .windows => "উইন্ডোজ", 35 | .linux => "লিনাক্স", //should be unix detection instead of linux 36 | .ios => "আইওএস", 37 | .macos => "ম্যাকওএস", 38 | .freebsd, .openbsd, .netbsd, .dragonfly => "বিএসডি", 39 | .plan9 => "প্ল্যান9", 40 | else => if (builtin.target.abi == .android) 41 | "আন্ড্রয়েড" 42 | else if (utils.IS_WASM) 43 | "ওয়েব" 44 | else 45 | "অজানা", 46 | }; 47 | 48 | const obj = vm.gc.copyStringU8(nm, nm.len) catch return PValue.makeNil(); 49 | return PValue.makeObj(obj.parent()); 50 | } 51 | 52 | pub const NameFuncArch = "আর্চ"; 53 | pub fn os_Arch(vm: *Vm, argc: u8, values: []PValue) PValue { 54 | _ = values; 55 | if (argc != 0) { 56 | return PValue.makeComptimeError( 57 | vm.gc, 58 | errs.OS_ARCH_ARG_NOT_ZERO, 59 | .{argc}, 60 | ).?; 61 | } 62 | 63 | const anm = switch (builtin.target.cpu.arch) { 64 | .arm, .armeb, .aarch64, .aarch64_be => "আর্ম", 65 | .x86 => "এক্স86", 66 | .x86_64 => "এক্স86_64", 67 | .wasm32, .wasm64 => "ওয়েব", 68 | else => "অজানা", 69 | }; 70 | 71 | return vm.gc.makeString(anm); 72 | } 73 | pub const NameFuncUsername = "ব্যবহারকারী"; 74 | pub fn os_Username(vm: *Vm, argc: u8, values: []PValue) PValue { 75 | _ = values; 76 | if (argc != 0) { 77 | return PValue.makeComptimeError( 78 | vm.gc, 79 | errs.OS_USERNAME_ARG_NOT_ZERO, 80 | .{argc}, 81 | ).?; 82 | } 83 | if (utils.IS_WASM) { 84 | return vm.gc.makeString("ওয়েব"); 85 | } 86 | 87 | var unm: ?[]const u8 = null; 88 | 89 | if (utils.IS_WIN) { 90 | unm = std.process.getEnvVarOwned(vm.gc.hal(), "USERNAME") catch null; 91 | } else if (utils.IS_MAC or utils.IS_LINUX) { 92 | unm = std.process.getEnvVarOwned(vm.gc.hal(), "USER") catch null; 93 | } 94 | 95 | if (unm) |n| { 96 | defer vm.gc.hal().free(n); 97 | return vm.gc.makeString(n); 98 | } else { 99 | return vm.gc.makeString("অজানা"); 100 | } 101 | } 102 | pub const NameFuncHomdir = "ঘর"; 103 | pub fn os_Homedir(vm: *Vm, argc: u8, values: []PValue) PValue { 104 | _ = values; 105 | if (argc != 0) { 106 | return PValue.makeComptimeError( 107 | vm.gc, 108 | errs.OS_HOMEDIR_ARG_NOT_ZERO, 109 | .{argc}, 110 | ).?; 111 | } 112 | if (utils.IS_WASM) { 113 | return vm.gc.makeString("ওয়েব"); 114 | } 115 | const hdir: ?[]const u8 = if (utils.IS_WIN) 116 | std.process.getEnvVarOwned(vm.gc.hal(), "USERPROFILE") catch null 117 | else if (utils.IS_MAC or utils.IS_LINUX) 118 | std.process.getEnvVarOwned(vm.gc.hal(), "HOME") catch null 119 | else 120 | null; 121 | 122 | if (hdir) |h| { 123 | defer vm.gc.hal().free(h); 124 | return vm.gc.makeString(h); 125 | } else { 126 | return vm.gc.makeString("অজানা"); 127 | } 128 | } 129 | pub const NameFuncCurdir = "বর্তমান"; 130 | pub fn os_Curdir(vm: *Vm, argc: u8, values: []PValue) PValue { 131 | _ = values; 132 | if (argc != 0) { 133 | return PValue.makeComptimeError( 134 | vm.gc, 135 | errs.OS_CURDIR_ARG_NOT_ZERO, 136 | .{argc}, 137 | ).?; 138 | } 139 | if (utils.IS_WASM) { 140 | return vm.gc.makeString("ওয়েব"); 141 | } 142 | 143 | const tempPath = vm.gc.hal().alloc(u8, 1024) catch { 144 | return vm.gc.makeString("অজানা"); 145 | }; 146 | 147 | const dir = std.process.getCwd(tempPath) catch return { 148 | vm.gc.hal().free(tempPath); 149 | return vm.gc.makeString("অজানা"); 150 | }; 151 | 152 | const result = vm.gc.makeString(dir); 153 | 154 | vm.gc.hal().free(tempPath); 155 | 156 | return result; 157 | } 158 | -------------------------------------------------------------------------------- /web/script.js: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) Palash Bauri 3 | // 4 | // This Source Code Form is subject to the terms of the Mozilla Public 5 | // License, v. 2.0. If a copy of the MPL was not distributed with this 6 | // file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | // 8 | // SPDX-License-Identifier: MPL-2.0 9 | 10 | 11 | const output = document.getElementById("output"); 12 | const button = document.getElementById("runbtn"); 13 | const clearButton = document.getElementById("clearbtn"); 14 | const inputBox = document.getElementById("codeinput"); 15 | const lineNumberElem = document.getElementById("line-numbers"); 16 | 17 | inputBox.value = `kaj ghumano(nayok) 18 | show(nayok + " is sleeping!") 19 | sesh 20 | 21 | ghumano("Palash"); 22 | `; 23 | 24 | const dc = new TextDecoder(); 25 | 26 | 27 | 28 | const inputBoxStyles = window.getComputedStyle(inputBox); 29 | 30 | [ 31 | 'fontFamily', 32 | 'fontSize', 33 | 'fontWeight', 34 | 'letterSpacing', 35 | 'lineHeight', 36 | 'padding', 37 | ].forEach((prop) => { 38 | lineNumberElem.style[prop] = inputBoxStyles[prop]; 39 | }); 40 | 41 | 42 | const parseValue = (val) => val.endsWith('px') ? parseInt(val.slice(0,-2) , 10) : 0; 43 | const font = `${inputBoxStyles.fontSize} ${inputBoxStyles.fontFamily}`; 44 | const paddingLeft = parseValue(inputBoxStyles.paddingLeft); 45 | const paddingRight = parseValue(inputBoxStyles.paddingRight); 46 | 47 | const canvas = document.createElement('canvas'); 48 | const context = canvas.getContext('2d'); 49 | context.font = font; 50 | 51 | const calcNumLines = (str) => { 52 | const textareaWidth = inputBox.getBoundingClientRect().width - paddingLeft - paddingRight; 53 | const words = str.split(' '); 54 | let lineCount = 0; 55 | let curLine = ''; 56 | for (let i = 0; i < words.length; i++){ 57 | const wordWidth = context.measureText(words[i] + ' ').width; 58 | const lineWidth = context.measureText(curLine).width; 59 | 60 | if (lineWidth + wordWidth > textareaWidth){ 61 | lineCount++; 62 | curLine = words[i] + ' '; 63 | } else { 64 | curLine += words[i] + ' '; 65 | } 66 | 67 | 68 | } 69 | 70 | if (curLine.trim() !== ''){ 71 | lineCount++; 72 | } 73 | 74 | return lineCount; 75 | }; 76 | 77 | const calcLineNumbers = () =>{ 78 | const lines = inputBox.value.split('\n'); 79 | const numLines = lines.map((line) => calcNumLines(line)); 80 | 81 | let lineNums = []; 82 | let i = 1; 83 | while ( numLines.length > 0 ) { 84 | const numLinesOfSentence = numLines.shift(); 85 | 86 | lineNums.push(i); 87 | 88 | if(numLinesOfSentence > 1){ 89 | Array(numLinesOfSentence - 1) 90 | .fill('') 91 | .forEach((_) => lineNums.push('')); 92 | } 93 | i++; 94 | } 95 | 96 | return lineNums; 97 | 98 | }; 99 | 100 | const displayLineNumbers = () =>{ 101 | const lines = calcLineNumbers(); 102 | lineNumberElem.innerHTML = Array.from({ 103 | length: lines.length, 104 | } , (_ , i) => `
${lines[i] || ' '}
`).join(""); 105 | } 106 | 107 | displayLineNumbers(); 108 | 109 | const ro = new ResizeObserver(() => { 110 | const rect = inputBox.getBoundingClientRect(); 111 | lineNumberElem.style.height = `${rect.height}px`; 112 | displayLineNumbers(); 113 | }); 114 | 115 | ro.observe(inputBox); 116 | 117 | inputBox.addEventListener('scroll' , () =>{ 118 | lineNumberElem.scrollTop = inputBox.scrollTop; 119 | }); 120 | 121 | inputBox.addEventListener('input' , () => { 122 | displayLineNumbers(); 123 | }); 124 | 125 | const importObject = { 126 | env : { 127 | writeStdout : (ptr , len) => { 128 | output.value += dc.decode( 129 | new Uint8Array(wasm.memory.buffer.slice(ptr, ptr + len)) 130 | ); 131 | 132 | 133 | }, 134 | 135 | writeStderr : (ptr , len) => { 136 | output.value += dc.decode( 137 | new Uint8Array(wasm.memory.buffer.slice(ptr, ptr + len)) 138 | ); 139 | }, 140 | 141 | getTimestamp : () =>{ 142 | return Date.now(); 143 | } 144 | } 145 | } 146 | 147 | const enc = new TextEncoder(); 148 | const makeString = (wasm , str) => { 149 | const strArr = enc.encode(str); 150 | const len = strArr.length; 151 | const ptr = wasm.memAlloc(len); 152 | 153 | if (ptr == 0) { 154 | output.innerText = "Failed to allocate memory"; 155 | } 156 | 157 | var m8 = new Uint8Array(wasm.memory.buffer); 158 | for(let i = 0; i < len ; i++){ 159 | m8[ptr + i] = strArr[i]; 160 | } 161 | 162 | return {ptr , len}; 163 | } 164 | 165 | function runCode(wasm , str){ 166 | var sourceStr = makeString(wasm , str); 167 | wasm.runCodeApi(sourceStr.ptr , sourceStr.len); 168 | wasm.memFree(sourceStr.ptr , sourceStr.len); 169 | } 170 | 171 | function main(wasm){ 172 | console.log("Module Loaded"); 173 | 174 | clearButton.addEventListener("click" , (_) =>{ 175 | output.value = ""; 176 | }); 177 | 178 | button.addEventListener("click" , (_) => { 179 | const src = inputBox.value; 180 | runCode(wasm , src); 181 | }); 182 | } 183 | 184 | 185 | fetch("./pankti.wasm") 186 | .then((resp) => WebAssembly.instantiateStreaming(resp , importObject)) 187 | .then((result) => { 188 | wasm = result.instance.exports; 189 | main(wasm); 190 | }); 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | -------------------------------------------------------------------------------- /src/stdlib/stdlib.zig: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) Palash Bauri 3 | // 4 | // This Source Code Form is subject to the terms of the Mozilla Public 5 | // License, v. 2.0. If a copy of the MPL was not distributed with this 6 | // file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | // 8 | // SPDX-License-Identifier: MPL-2.0 9 | 10 | const std = @import("std"); 11 | 12 | const vm = @import("../vm.zig"); 13 | const utils = @import("../utils.zig"); 14 | const gc = @import("../gc.zig"); 15 | const table = @import("../table.zig"); 16 | const PObj = @import("../object.zig").PObj; 17 | 18 | const osMod = @import("os.zig"); 19 | const mathMod = @import("math.zig"); 20 | const stringMod = @import("string.zig"); 21 | const mapMod = @import("map.zig"); 22 | const bigMod = @import("big.zig"); 23 | //const fileMod = @import("file.zig"); 24 | 25 | pub const msl = struct { 26 | key: []const u8, 27 | func: PObj.ONativeFunction.NativeFn, 28 | 29 | pub fn m(key: []const u8, func: PObj.ONativeFunction.NativeFn) msl { 30 | return msl{ 31 | .key = key, 32 | .func = func, 33 | }; 34 | } 35 | }; 36 | 37 | pub fn _addStdlib( 38 | v: *vm.Vm, 39 | tab: *table.PankTable(), 40 | name: []const u8, 41 | func: PObj.ONativeFunction.NativeFn, 42 | ) !void { 43 | const nstr = try v.gc.copyString(name, @truncate(name.len)); 44 | 45 | try v.stack.push(nstr.parent().asValue()); 46 | const nf = v.gc.newNative(v, func) orelse return; 47 | try v.stack.push(nf); 48 | 49 | try tab.put( 50 | v.gc.hal(), 51 | v.peek(1).asObj().asString(), 52 | v.peek(0), 53 | ); 54 | 55 | _ = try v.stack.pop(); 56 | _ = try v.stack.pop(); 57 | } 58 | 59 | fn _pushStdlib(v: *vm.Vm, modname: []const u8, items: []const msl) void { 60 | const nameHash = utils.hashChars(modname, v.gc) catch return; 61 | 62 | //std.debug.print("HASH AT PUSH->{d}\n" , .{nameHash}); 63 | v.gc.stdlibs[v.gc.stdlibCount] = gc.StdLibMod.new(); 64 | v.gc.stdlibs[v.gc.stdlibCount].name = modname; 65 | v.gc.stdlibs[v.gc.stdlibCount].hash = nameHash; 66 | v.gc.stdlibs[v.gc.stdlibCount].ownerCount = 0; 67 | 68 | v.gc.stdlibCount += 1; 69 | var i: usize = 0; 70 | 71 | while (i < items.len) : (i += 1) { 72 | _addStdlib( 73 | v, 74 | &v.gc.stdlibs[v.gc.stdlibCount - 1].items, 75 | items[i].key, 76 | items[i].func, 77 | ) catch { 78 | return; 79 | }; 80 | } 81 | } 82 | 83 | pub const OsName = osMod.Name; 84 | pub const MathName = mathMod.Name; 85 | pub const StringName = stringMod.Name; 86 | pub const MapName = mapMod.Name; 87 | pub const BigName = bigMod.Name; 88 | //pub const FileName = fileMod.Name; 89 | 90 | pub fn IsStdlib(name: []const u8) bool { 91 | if (utils.matchU8(name, OsName) or 92 | utils.matchU8(name, MathName) or 93 | utils.matchU8(name, StringName) or 94 | utils.matchU8(name, MapName) or 95 | utils.matchU8(name, BigName)) 96 | //utils.matchU8(name, FileName)) 97 | { 98 | return true; 99 | } 100 | 101 | return false; 102 | } 103 | 104 | pub fn PushStdlib(v: *vm.Vm, name: []const u8) bool { 105 | if (utils.matchU8(name, OsName)) { 106 | pushStdlibOs(v); 107 | return true; 108 | } else if (utils.matchU8(name, MathName)) { 109 | pushStdlibMath(v); 110 | return true; 111 | } else if (utils.matchU8(name, StringName)) { 112 | pushStdlibString(v); 113 | return true; 114 | } else if (utils.matchU8(name, MapName)) { 115 | pushStdlibMap(v); 116 | return true; 117 | } else if (utils.matchU8(name, BigName)) { 118 | pushStdlibBig(v); 119 | return true; 120 | // } else if (utils.matchU8(name, FileName)) { 121 | // pushStdlibFile(v); 122 | // return true; 123 | // } 124 | } 125 | 126 | return false; 127 | } 128 | 129 | pub fn pushStdlibOs(v: *vm.Vm) void { 130 | _pushStdlib(v, osMod.Name, &[_]msl{ 131 | msl.m(osMod.NameFuncName, osMod.os_Name), 132 | msl.m(osMod.NameFuncArch, osMod.os_Arch), 133 | msl.m(osMod.NameFuncUsername, osMod.os_Username), 134 | msl.m(osMod.NameFuncHomdir, osMod.os_Homedir), 135 | msl.m(osMod.NameFuncCurdir, osMod.os_Curdir), 136 | }); 137 | } 138 | 139 | pub fn pushStdlibMath(v: *vm.Vm) void { 140 | _pushStdlib(v, mathMod.Name, &[_]msl{ 141 | msl.m(mathMod.NameFuncPi, mathMod.math_Pi), 142 | msl.m(mathMod.NameFuncE, mathMod.math_E), 143 | msl.m(mathMod.NameFuncSqrt, mathMod.math_Sqrt), 144 | msl.m(mathMod.NameFuncLog10, mathMod.math_Log10), 145 | msl.m(mathMod.NameFuncLog, mathMod.math_Log), 146 | msl.m(mathMod.NameFuncLogX, mathMod.math_LogX), 147 | msl.m(mathMod.NameFuncGcd, mathMod.math_Gcd), 148 | msl.m(mathMod.NameFuncLcm, mathMod.math_Lcm), 149 | msl.m(mathMod.NameFuncSine, mathMod.math_Sine), 150 | msl.m(mathMod.NameFuncCosine, mathMod.math_Cosine), 151 | msl.m(mathMod.NameFuncTangent, mathMod.math_Tangent), 152 | msl.m(mathMod.NameFuncDegree, mathMod.math_Degree), 153 | msl.m(mathMod.NameFuncRadians, mathMod.math_Radians), 154 | msl.m(mathMod.NameFuncNumber, mathMod.math_Number), 155 | msl.m(mathMod.NameFuncAbs, mathMod.math_Abs), 156 | msl.m(mathMod.NameFuncRound, mathMod.math_Round), 157 | msl.m(mathMod.NameFuncFloor, mathMod.math_Floor), 158 | msl.m(mathMod.NameFuncCeil, mathMod.math_Ceil), 159 | }); 160 | } 161 | 162 | pub fn pushStdlibString(v: *vm.Vm) void { 163 | _pushStdlib(v, stringMod.Name, &[_]msl{ 164 | msl.m(stringMod.NameFuncSplit, stringMod.str_Split), 165 | msl.m(stringMod.NameFuncString, stringMod.str_String), 166 | msl.m(stringMod.NameFuncUnicode, stringMod.str_Unicode), 167 | }); 168 | } 169 | 170 | // pub fn pushStdlibFile(v: *vm.Vm) void { 171 | // _pushStdlib(v, fileMod.Name, &[_]msl{ 172 | // msl.m(fileMod.NameFuncRead, fileMod.file_Read), 173 | // msl.m(fileMod.NameFuncWrite, fileMod.file_Write), 174 | // }); 175 | // } 176 | 177 | pub fn pushStdlibMap(v: *vm.Vm) void { 178 | _pushStdlib(v, mapMod.Name, &[_]msl{ 179 | msl.m(mapMod.NameFuncExists, mapMod.map_Exists), 180 | msl.m(mapMod.NameFuncKeys, mapMod.map_Keys), 181 | msl.m(mapMod.NameFuncValues, mapMod.map_Values), 182 | }); 183 | } 184 | 185 | pub fn pushStdlibBig(v: *vm.Vm) void { 186 | _pushStdlib(v, bigMod.Name, &[_]msl{ 187 | msl.m(bigMod.NameFuncNew, bigMod.big_New), 188 | msl.m(bigMod.NamefuncAdd, bigMod.big_Add), 189 | msl.m(bigMod.NamefuncSub, bigMod.big_Sub), 190 | msl.m(bigMod.NamefuncDiv, bigMod.big_Div), 191 | msl.m(bigMod.NamefuncMul, bigMod.big_Mul), 192 | msl.m(bigMod.NamefuncSqrt, bigMod.big_Sqrt), 193 | }); 194 | } 195 | -------------------------------------------------------------------------------- /windows/windows.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 16.0 23 | Win32Proj 24 | {5f8fab4e-4d08-4044-ad6d-428c6ff56531} 25 | windows 26 | 10.0 27 | pankti 28 | 29 | 30 | 31 | Application 32 | true 33 | v143 34 | Unicode 35 | 36 | 37 | Application 38 | false 39 | v143 40 | true 41 | Unicode 42 | 43 | 44 | Application 45 | true 46 | v143 47 | Unicode 48 | 49 | 50 | Application 51 | false 52 | v143 53 | true 54 | Unicode 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | Level3 77 | true 78 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 79 | true 80 | 81 | 82 | Console 83 | true 84 | 85 | 86 | 87 | 88 | Level3 89 | true 90 | true 91 | true 92 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 93 | true 94 | 95 | 96 | Console 97 | true 98 | true 99 | true 100 | 101 | 102 | 103 | 104 | Level3 105 | true 106 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 107 | true 108 | 109 | 110 | Console 111 | true 112 | 113 | 114 | 115 | 116 | Level3 117 | true 118 | true 119 | true 120 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 121 | true 122 | 123 | 124 | Console 125 | true 126 | true 127 | true 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | -------------------------------------------------------------------------------- /src/stdlib/string.zig: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) Palash Bauri 3 | // 4 | // This Source Code Form is subject to the terms of the Mozilla Public 5 | // License, v. 2.0. If a copy of the MPL was not distributed with this 6 | // file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | // 8 | // SPDX-License-Identifier: MPL-2.0 9 | 10 | const std = @import("std"); 11 | const value = @import("../value.zig"); 12 | const Vm = @import("../vm.zig").Vm; 13 | const PValue = value.PValue; 14 | const utils = @import("../utils.zig"); 15 | const stdlib = @import("stdlib.zig"); 16 | const PObj = @import("../object.zig").PObj; 17 | const errs = @import("string_errors.zig"); 18 | 19 | //স্ট্রিং 20 | pub const Name = "স্ট্রিং"; 21 | 22 | // pub const NameFuncIndex = "index"; 23 | // pub fn str_Index(vm : *Vm , argc : u8, values : []PValue) PValue { 24 | // if (argc != 2) { 25 | // return PValue.makeComptimeError(vm.gc, "index(..) expected 2 args but got {d}" , .{argc},).?; 26 | // } 27 | // 28 | // const rawString = values[0]; 29 | // const rawIndex = values[1]; 30 | // 31 | // if (!rawString.isString()) { 32 | // return PValue.makeComptimeError( 33 | // vm.gc, 34 | // "1st argument must be string", 35 | // .{}, 36 | // ).?; 37 | // } 38 | // 39 | // if (!rawIndex.isNumber()) { 40 | // return PValue.makeComptimeError( 41 | // vm.gc, 42 | // "2nd argument must be number", 43 | // .{}, 44 | // ).?; 45 | // } 46 | // 47 | // const str = rawString.asObj().asString(); 48 | // const _index = rawIndex.asNumber(); 49 | // 50 | // if (!utils.isInt(_index)) { 51 | // return PValue.makeComptimeError( 52 | // vm.gc, 53 | // "Index must be a integer", 54 | // .{}, 55 | // ).?; 56 | // } 57 | // 58 | // const _n = utils.asInt(_index); 59 | // 60 | // if (_n < 0) { 61 | // return PValue.makeComptimeError( 62 | // vm.gc, 63 | // "Index must be positive number", 64 | // .{}, 65 | // ).?; 66 | // } 67 | // 68 | // const index = utils.asUint(_index); 69 | // 70 | // } 71 | 72 | pub const NameFuncUnicode = "ইউনিকোড"; 73 | 74 | pub fn str_Unicode(vm: *Vm, argc: u8, values: []PValue) PValue { 75 | if (argc != 1) { 76 | return PValue.makeComptimeError( 77 | vm.gc, 78 | "Unicode Function takes a single argument", 79 | .{}, 80 | ).?; 81 | } 82 | 83 | const rawUc = values[0]; 84 | 85 | if (!rawUc.isNumber()) { 86 | return PValue.makeComptimeError( 87 | vm.gc, 88 | "First argument must be number", 89 | .{}, 90 | ).?; 91 | } 92 | 93 | const raw_num = rawUc.asNumber(); 94 | 95 | if (!utils.isInt(raw_num)) { 96 | return PValue.makeComptimeError( 97 | vm.gc, 98 | "Unicode number must be a integer", 99 | .{}, 100 | ).?; 101 | } 102 | 103 | const number = utils.asInt(raw_num); 104 | 105 | if (number < 0 or number > 1114111) { 106 | return PValue.makeComptimeError( 107 | vm.gc, 108 | "Invalid unicode codepoint", 109 | .{}, 110 | ).?; 111 | } 112 | 113 | const uf: u21 = @truncate(utils.asUint(raw_num)); 114 | 115 | var a = [_]u8{ 0, 0, 0, 0 }; 116 | const len = std.unicode.utf8Encode(uf, &a) catch { 117 | return PValue.makeComptimeError( 118 | vm.gc, 119 | "Invalid unicode codepoint", 120 | .{}, 121 | ).?; 122 | }; 123 | 124 | const r = vm.gc.copyString( 125 | a[0..len], 126 | len, 127 | ) catch { 128 | return PValue.makeComptimeError( 129 | vm.gc, 130 | "Failed to create string from unicode codepoint", 131 | .{}, 132 | ).?; 133 | }; 134 | 135 | return PValue.makeObj(r.parent()); 136 | } 137 | 138 | pub const NameFuncString = "স্ট্রিং"; 139 | pub fn str_String(vm: *Vm, argc: u8, values: []PValue) PValue { 140 | if (argc != 1) { 141 | return PValue.makeComptimeError( 142 | vm.gc, 143 | errs.STR_STRING_ACCEPTS_SINGLE_ARG, 144 | .{argc}, 145 | ).?; 146 | } 147 | 148 | const rawString = values[0].toString(vm.gc.hal()) catch { 149 | return vm.gc.makeString(""); 150 | }; 151 | //const myString = utils.u8tou32(rawString, vm.gc.hal()) catch { 152 | // vm.gc.hal().free(rawString); 153 | // return vm.gc.makeString(""); 154 | //}; 155 | const myString = rawString; 156 | const strObj = vm.gc.copyString( 157 | myString, 158 | @intCast(myString.len), 159 | ) catch { 160 | vm.gc.hal().free(rawString); 161 | return vm.gc.makeString(""); 162 | }; 163 | 164 | vm.stack.push(PValue.makeObj(strObj.parent())) catch { 165 | vm.gc.hal().free(rawString); 166 | return vm.gc.makeString(""); 167 | }; 168 | 169 | vm.gc.hal().free(rawString); 170 | //vm.gc.hal().free(myString); 171 | 172 | return vm.stack.pop() catch return vm.gc.makeString(""); 173 | } 174 | pub const NameFuncSplit = "ভাগ"; 175 | pub fn str_Split(vm: *Vm, argc: u8, values: []PValue) PValue { 176 | if (argc != 2) { 177 | return PValue.makeComptimeError( 178 | vm.gc, 179 | errs.STR_SPLIT_ACCEPTS_TWO_ARGS, 180 | .{argc}, 181 | ).?; 182 | } 183 | 184 | if (!values[0].isString() or !values[0].isString()) { 185 | const aS = values[0].toString(vm.gc.hal()) catch { 186 | return PValue.makeComptimeError( 187 | vm.gc, 188 | errs.STR_SPLIT_INT_CONVERT_A_ERROR, 189 | .{}, 190 | ).?; 191 | }; 192 | 193 | const bS = values[1].toString(vm.gc.hal()) catch { 194 | return PValue.makeComptimeError( 195 | vm.gc, 196 | errs.STR_SPLIT_INT_CONVERT_B_ERROR, 197 | .{}, 198 | ).?; 199 | }; 200 | const err = PValue.makeComptimeError( 201 | vm.gc, 202 | errs.STR_SPLIT_NOT_STRING_ARGS, 203 | .{ 204 | aS, 205 | values[0].getTypeAsSimpleStr(), 206 | bS, 207 | values[1].getTypeAsSimpleStr(), 208 | }, 209 | ); 210 | 211 | vm.gc.hal().free(aS); 212 | vm.gc.hal().free(bS); 213 | 214 | return err.?; 215 | } 216 | 217 | const rawString = values[0].asObj().asString(); 218 | 219 | const rawDelim = values[1].asObj().asString(); 220 | 221 | var objArr = vm.gc.newObj( 222 | PObj.OType.Ot_Array, 223 | PObj.OArray, 224 | ) catch { 225 | return PValue.makeNil(); 226 | }; 227 | 228 | objArr.init(); 229 | 230 | vm.stack.push(PValue.makeObj(objArr.parent())) catch { 231 | return PValue.makeNil(); 232 | }; 233 | 234 | var ite = std.mem.splitAny(u8, rawString.chars, rawDelim.chars); 235 | while (ite.next()) |s| { 236 | const objString = vm.gc.copyString(s, @intCast(s.len)) catch { 237 | return PValue.makeNil(); 238 | }; 239 | vm.stack.push(PValue.makeObj(objString.parent())) catch { 240 | return PValue.makeNil(); 241 | }; 242 | if (!objArr.addItem(vm.gc, vm.stack.pop() catch { 243 | return PValue.makeNil(); 244 | })) { 245 | return PValue.makeNil(); 246 | } 247 | } 248 | 249 | return vm.stack.pop() catch return PValue.makeNil(); 250 | } 251 | -------------------------------------------------------------------------------- /src/stdlib/file.zig: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) Palash Bauri 3 | // 4 | // This Source Code Form is subject to the terms of the Mozilla Public 5 | // License, v. 2.0. If a copy of the MPL was not distributed with this 6 | // file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | // 8 | // SPDX-License-Identifier: MPL-2.0 9 | 10 | const std = @import("std"); 11 | const value = @import("../value.zig"); 12 | const Vm = @import("../vm.zig").Vm; 13 | const PValue = value.PValue; 14 | const utils = @import("../utils.zig"); 15 | 16 | pub const Name: []const u8 = "file"; 17 | 18 | fn fileExists(path: []const u8) ?std.fs.File.Stat { 19 | const stat = std.fs.cwd().statFile(path) catch { 20 | return null; 21 | }; 22 | 23 | return stat; 24 | } 25 | 26 | pub const NameFuncWrite: []const u8 = "write"; 27 | pub fn file_Write(vm: *Vm, argc: u8, values: []PValue) PValue { 28 | if (utils.IS_WASM) { 29 | return PValue.makeError(vm.gc, "write(...) is not supported on web editor").?; 30 | } 31 | 32 | if (argc != 3) { 33 | return PValue.makeError(vm.gc, "write(path, content , mode) requires a 3 arguments").?; 34 | } 35 | 36 | if (!values[0].isObj()) { 37 | return PValue.makeError(vm.gc, "write(path, ... , ...) first argument \"path\" must be a string").?; 38 | } 39 | 40 | if (!values[0].asObj().isString()) { 41 | return PValue.makeError(vm.gc, "write(path, ... , ...) first argument \"path\" must be a string").?; 42 | } 43 | 44 | if (!values[1].asObj().isString()) { 45 | return PValue.makeError(vm.gc, "write(..., content , ...) second argument \"content\" must be a string").?; 46 | } 47 | 48 | if (!values[1].isObj()) { 49 | return PValue.makeError(vm.gc, "write(..., content , ...) second argument \"content\" must be a string").?; 50 | } 51 | 52 | if (!values[2].isObj()) { 53 | return PValue.makeError(vm.gc, "write(..., ... , mode) third argument \"mode\" must be a string").?; 54 | } 55 | 56 | if (!values[2].asObj().isString()) { 57 | return PValue.makeError(vm.gc, "write(..., ... , mode) third argument \"mode\" must be a string").?; 58 | } 59 | 60 | const rawFileMode = values[2].toString(vm.gc.hal()) catch { 61 | return PValue.makeError(vm.gc, "Failed to read `mode`").?; 62 | }; 63 | 64 | if (rawFileMode.len != 1) { 65 | return PValue.makeError(vm.gc, "Invalid file mode in write(...) function; must be either 'w' or 'a'").?; 66 | } 67 | 68 | var fileMode: u8 = 'w'; 69 | 70 | if (rawFileMode[0] != 'w' and rawFileMode[0] != 'a') { 71 | vm.gc.hal().free(rawFileMode); 72 | return PValue.makeError(vm.gc, "Invalid file mode in write(...) function; must be either 'w' or 'a'").?; 73 | } 74 | 75 | if (rawFileMode[0] == 'a') { 76 | fileMode = 'a'; 77 | } 78 | 79 | vm.gc.hal().free(rawFileMode); 80 | 81 | const rawFilePath = values[0].toString(vm.gc.hal()) catch { 82 | return PValue.makeError(vm.gc, "Failed to read file name in write(...)").?; 83 | }; 84 | 85 | var file: std.fs.File = undefined; 86 | 87 | if (fileMode == 'w') { 88 | file = std.fs.cwd().createFile(rawFilePath, .{}) catch { 89 | vm.gc.hal().free(rawFilePath); 90 | return PValue.makeError(vm.gc, "failed to create a new file specified in write(...)").?; 91 | }; 92 | } else { 93 | file = std.fs.cwd().openFile(rawFilePath, .{ .mode = .read_write }) catch { 94 | vm.gc.hal().free(rawFilePath); 95 | return PValue.makeError(vm.gc, "failed to open file specified in write(...)").?; 96 | }; 97 | } 98 | 99 | const content = values[1].asObj().toString(vm.gc.hal()) catch { 100 | vm.gc.hal().free(rawFilePath); 101 | return PValue.makeError(vm.gc, "Failed to read content to write in write(...)").?; 102 | }; 103 | 104 | var written: usize = 0; 105 | 106 | if (fileMode == 'w') { 107 | written = file.write(content) catch { 108 | vm.gc.hal().free(rawFilePath); 109 | vm.gc.hal().free(content); 110 | return PValue.makeError(vm.gc, "Failed to write to file specified in write(...)").?; 111 | }; 112 | } else { 113 | const stat = file.stat() catch { 114 | vm.gc.hal().free(rawFilePath); 115 | vm.gc.hal().free(content); 116 | return PValue.makeError(vm.gc, "Failed to get file information for appending for write(...)").?; 117 | }; 118 | 119 | file.seekTo(stat.size) catch { 120 | vm.gc.hal().free(rawFilePath); 121 | vm.gc.hal().free(content); 122 | return PValue.makeError(vm.gc, "Failed to write to file specified in write(...)").?; 123 | }; 124 | 125 | written = file.write(content) catch { 126 | vm.gc.hal().free(rawFilePath); 127 | vm.gc.hal().free(content); 128 | return PValue.makeError(vm.gc, "Failed to write to file specified in write(...)").?; 129 | }; 130 | } 131 | 132 | file.sync() catch return { 133 | vm.gc.hal().free(rawFilePath); 134 | vm.gc.hal().free(content); 135 | return PValue.makeError(vm.gc, "Failed to sync file data after writing for write(...)").?; 136 | }; 137 | 138 | const bw = @as(f64, @floatFromInt(written)); 139 | vm.gc.hal().free(rawFilePath); 140 | vm.gc.hal().free(content); 141 | 142 | return PValue.makeNumber(bw); 143 | } 144 | 145 | pub const NameFuncRead: []const u8 = "read"; 146 | pub fn file_Read(vm: *Vm, argc: u8, values: []PValue) PValue { 147 | if (utils.IS_WASM) { 148 | return PValue.makeError(vm.gc, "file(path) is not supported on web editor").?; 149 | } 150 | if (argc != 1) { 151 | return PValue.makeError(vm.gc, "read(path) requires a single argument").?; 152 | } 153 | 154 | if (!values[0].isObj()) { 155 | return PValue.makeError(vm.gc, "read(path) first argument must be a string").?; 156 | } 157 | 158 | if (!values[0].asObj().isString()) { 159 | return PValue.makeError(vm.gc, "read(path) first argument must be a string").?; 160 | } 161 | 162 | const rawFilePath = values[0].toString(vm.gc.hal()) catch return vm.gc.makeString(""); 163 | 164 | const path = std.fs.cwd().openFile(rawFilePath, .{}) catch { 165 | vm.gc.hal().free(rawFilePath); 166 | return PValue.makeError(vm.gc, "read(...) failed to read the file specified").?; 167 | }; 168 | defer path.close(); 169 | 170 | const fileContent = path.readToEndAlloc(vm.gc.hal(), std.math.maxInt(usize)) catch { 171 | vm.gc.hal().free(rawFilePath); 172 | return PValue.makeError(vm.gc, "read(...) failed to read the file specified").?; 173 | }; 174 | 175 | const f = utils.u8tou32(fileContent, vm.gc.hal()) catch { 176 | vm.gc.hal().free(rawFilePath); 177 | vm.gc.hal().free(fileContent); 178 | 179 | return PValue.makeError(vm.gc, "read(...) failed to convert file content to object").?; 180 | }; 181 | 182 | const strObj = vm.gc.copyString(f, @intCast(f.len)) catch { 183 | vm.gc.hal().free(rawFilePath); 184 | vm.gc.hal().free(fileContent); 185 | vm.gc.hal().free(f); 186 | return PValue.makeError(vm.gc, "read(...) failed to convert file content to string object").?; 187 | }; 188 | 189 | vm.stack.push(PValue.makeObj(strObj.parent())) catch { 190 | vm.gc.hal().free(rawFilePath); 191 | vm.gc.hal().free(fileContent); 192 | vm.gc.hal().free(f); 193 | return PValue.makeError(vm.gc, "read(...) failed to save file content to memory").?; 194 | }; 195 | 196 | vm.gc.hal().free(rawFilePath); 197 | vm.gc.hal().free(fileContent); 198 | vm.gc.hal().free(f); 199 | 200 | return vm.stack.pop() catch return { 201 | return PValue.makeError(vm.gc, "read(...) failed to fetch file content to memory").?; 202 | }; 203 | } 204 | -------------------------------------------------------------------------------- /src/stdlib/big.zig: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) Palash Bauri 3 | // 4 | // This Source Code Form is subject to the terms of the Mozilla Public 5 | // License, v. 2.0. If a copy of the MPL was not distributed with this 6 | // file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | // 8 | // SPDX-License-Identifier: MPL-2.0 9 | 10 | const std = @import("std"); 11 | const big = std.math.big; 12 | const value = @import("../value.zig"); 13 | const Vm = @import("../vm.zig").Vm; 14 | const PValue = value.PValue; 15 | const utils = @import("../utils.zig"); 16 | const stdlib = @import("stdlib.zig"); 17 | const PObj = @import("../object.zig").PObj; 18 | 19 | //বড় 20 | pub const Name: []const u8 = "বড়"; 21 | 22 | pub const NamefuncSub: []const u8 = "বিয়োগ"; 23 | pub fn big_Sub(vm: *Vm, argc: u8, values: []PValue) PValue { 24 | if (argc != 2) { 25 | return PValue.makeError( 26 | vm.gc, 27 | "বিয়োগ(ক , খ) কাজটি মাত্র দুটি চলরাশি গ্রহণ করে।", 28 | ).?; 29 | } 30 | 31 | const a = values[0]; 32 | const b = values[1]; 33 | 34 | if (!a.isObj() or !a.asObj().isBigInt()) { 35 | return PValue.makeError( 36 | vm.gc, 37 | "বিয়োগ(ক , খ) কাজটি মাত্র বড় সংখ্যা গ্রহণ করে", 38 | ).?; 39 | } 40 | 41 | if (!b.isObj() or !b.asObj().isBigInt()) { 42 | return PValue.makeError( 43 | vm.gc, 44 | "বিয়োগ(ক , খ) কাজটি মাত্র বড় সংখ্যা গ্রহণ করে", 45 | ).?; 46 | } 47 | 48 | const aInt = a.asObj().asBigInt(); 49 | const bInt = b.asObj().asBigInt(); 50 | 51 | const x: *PObj.OBigInt = vm.gc.newObj(.Ot_BigInt, PObj.OBigInt) catch { 52 | return PValue.makeNil(); 53 | }; 54 | 55 | if (!x.initInt(vm.gc)) return PValue.makeNil(); 56 | 57 | x.ival.sub(&aInt.ival, &bInt.ival) catch return PValue.makeNil(); 58 | 59 | vm.stack.push(x.parent().asValue()) catch return PValue.makeNil(); 60 | 61 | return vm.stack.pop() catch return PValue.makeNil(); 62 | } 63 | 64 | pub const NamefuncAdd: []const u8 = "যোগ"; 65 | pub fn big_Add(vm: *Vm, argc: u8, values: []PValue) PValue { 66 | if (argc != 2) { 67 | return PValue.makeError( 68 | vm.gc, 69 | "যোগ(ক , খ) কাজটি মাত্র দুটি চলরাশি গ্রহণ করে।", 70 | ).?; 71 | } 72 | 73 | const a = values[0]; 74 | const b = values[1]; 75 | 76 | if (!a.isObj() or !a.asObj().isBigInt()) { 77 | return PValue.makeError( 78 | vm.gc, 79 | "যোগ(ক , খ) কাজটি মাত্র বড় সংখ্যা গ্রহণ করে", 80 | ).?; 81 | } 82 | 83 | if (!b.isObj() or !b.asObj().isBigInt()) { 84 | return PValue.makeError( 85 | vm.gc, 86 | "যোগ(ক , খ) কাজটি মাত্র বড় সংখ্যা গ্রহণ করে", 87 | ).?; 88 | } 89 | const aInt = a.asObj().asBigInt(); 90 | const bInt = b.asObj().asBigInt(); 91 | 92 | const x: *PObj.OBigInt = vm.gc.newObj(.Ot_BigInt, PObj.OBigInt) catch { 93 | return PValue.makeNil(); 94 | }; 95 | 96 | if (!x.initInt(vm.gc)) return PValue.makeNil(); 97 | 98 | x.ival.add(&aInt.ival, &bInt.ival) catch { 99 | return PValue.makeNil(); 100 | }; 101 | 102 | vm.stack.push(x.parent().asValue()) catch return PValue.makeNil(); 103 | 104 | return vm.stack.pop() catch return PValue.makeNil(); 105 | } 106 | 107 | pub const NamefuncDiv: []const u8 = "ভাগ"; 108 | pub fn big_Div(vm: *Vm, argc: u8, values: []PValue) PValue { 109 | if (argc != 2) { 110 | return PValue.makeError( 111 | vm.gc, 112 | "ভাগ(ক , খ) কাজটি মাত্র দুটি চলরাশি গ্রহণ করে।", 113 | ).?; 114 | } 115 | 116 | const a = values[0]; 117 | const b = values[1]; 118 | 119 | if (!a.isObj() or !a.asObj().isBigInt()) { 120 | return PValue.makeError( 121 | vm.gc, 122 | "ভাগ(ক , খ) কাজটি মাত্র বড় সংখ্যা গ্রহণ করে", 123 | ).?; 124 | } 125 | 126 | if (!b.isObj() or !b.asObj().isBigInt()) { 127 | return PValue.makeError( 128 | vm.gc, 129 | "ভাগ(ক , খ) কাজটি মাত্র বড় সংখ্যা গ্রহণ করে", 130 | ).?; 131 | } 132 | const aInt = a.asObj().asBigInt(); 133 | const bInt = b.asObj().asBigInt(); 134 | 135 | const x: *PObj.OBigInt = vm.gc.newObj(.Ot_BigInt, PObj.OBigInt) catch { 136 | return PValue.makeNil(); 137 | }; 138 | 139 | if (!x.initInt(vm.gc)) return PValue.makeNil(); 140 | 141 | var temp = big.int.Managed.init(vm.gc.hal()) catch { 142 | return PValue.makeNil(); 143 | }; 144 | 145 | defer temp.deinit(); 146 | 147 | x.ival.divFloor(&temp, &aInt.ival, &bInt.ival) catch { 148 | return PValue.makeNil(); 149 | }; 150 | 151 | vm.stack.push(x.parent().asValue()) catch return PValue.makeNil(); 152 | 153 | return vm.stack.pop() catch return PValue.makeNil(); 154 | } 155 | 156 | pub const NamefuncRem: []const u8 = "ভাগশেষ"; 157 | pub fn big_Rem(vm: *Vm, argc: u8, values: []PValue) PValue { 158 | if (argc != 2) { 159 | return PValue.makeError( 160 | vm.gc, 161 | "ভাগশেষ(ক , খ) কাজটি মাত্র দুটি চলরাশি গ্রহণ করে।", 162 | ).?; 163 | } 164 | 165 | const a = values[0]; 166 | const b = values[1]; 167 | 168 | if (!a.isObj() or !a.asObj().isBigInt()) { 169 | return PValue.makeError( 170 | vm.gc, 171 | "ভাগশেষ(ক , খ) কাজটি মাত্র বড় সংখ্যা গ্রহণ করে", 172 | ).?; 173 | } 174 | 175 | if (!b.isObj() or !b.asObj().isBigInt()) { 176 | return PValue.makeError( 177 | vm.gc, 178 | "ভাগশেষ(ক , খ) কাজটি মাত্র বড় সংখ্যা গ্রহণ করে", 179 | ).?; 180 | } 181 | const aInt = a.asObj().asBigInt(); 182 | const bInt = b.asObj().asBigInt(); 183 | 184 | const x: *PObj.OBigInt = vm.gc.newObj(.Ot_BigInt, PObj.OBigInt) catch { 185 | return PValue.makeNil(); 186 | }; 187 | 188 | if (!x.initInt(vm.gc)) return PValue.makeNil(); 189 | 190 | var temp = big.int.Managed.init(vm.gc.hal()) catch { 191 | return PValue.makeNil(); 192 | }; 193 | 194 | defer temp.deinit(); 195 | 196 | temp.ival.divFloor(&x.ival, &aInt.ival, &bInt.ival) catch { 197 | return PValue.makeNil(); 198 | }; 199 | 200 | vm.stack.push(x.parent().asValue()) catch return PValue.makeNil(); 201 | 202 | return vm.stack.pop() catch return PValue.makeNil(); 203 | } 204 | 205 | pub const NamefuncMul: []const u8 = "গুন"; 206 | pub fn big_Mul(vm: *Vm, argc: u8, values: []PValue) PValue { 207 | if (argc != 2) { 208 | return PValue.makeError( 209 | vm.gc, 210 | "গুন(ক , খ) কাজটি মাত্র দুটি চলরাশি গ্রহণ করে।", 211 | ).?; 212 | } 213 | 214 | const a = values[0]; 215 | const b = values[1]; 216 | 217 | if (!a.isObj() or !a.asObj().isBigInt()) { 218 | return PValue.makeError( 219 | vm.gc, 220 | "গুন(ক , খ) কাজটি মাত্র বড় সংখ্যা গ্রহণ করে", 221 | ).?; 222 | } 223 | 224 | if (!b.isObj() or !b.asObj().isBigInt()) { 225 | return PValue.makeError( 226 | vm.gc, 227 | "গুন(ক , খ) কাজটি মাত্র বড় সংখ্যা গ্রহণ করে", 228 | ).?; 229 | } 230 | const aInt = a.asObj().asBigInt(); 231 | const bInt = b.asObj().asBigInt(); 232 | 233 | const x: *PObj.OBigInt = vm.gc.newObj(.Ot_BigInt, PObj.OBigInt) catch { 234 | return PValue.makeNil(); 235 | }; 236 | 237 | if (!x.initInt(vm.gc)) return PValue.makeNil(); 238 | 239 | x.ival.mul(&aInt.ival, &bInt.ival) catch { 240 | return PValue.makeNil(); 241 | }; 242 | 243 | vm.stack.push(x.parent().asValue()) catch return PValue.makeNil(); 244 | 245 | return vm.stack.pop() catch return PValue.makeNil(); 246 | } 247 | 248 | pub const NamefuncSqrt: []const u8 = "বর্গমূল"; 249 | pub fn big_Sqrt(vm: *Vm, argc: u8, values: []PValue) PValue { 250 | if (argc != 1) { 251 | return PValue.makeError( 252 | vm.gc, 253 | "বর্গমূল(ক) কাজটি মাত্র দুটি চলরাশি গ্রহণ করে।", 254 | ).?; 255 | } 256 | 257 | const a = values[0]; 258 | 259 | if (!a.isObj() or !a.asObj().isBigInt()) { 260 | return PValue.makeError( 261 | vm.gc, 262 | "বর্গমূল(ক) কাজটি মাত্র বড় সংখ্যা গ্রহণ করে", 263 | ).?; 264 | } 265 | 266 | const aInt = a.asObj().asBigInt(); 267 | 268 | const x: *PObj.OBigInt = vm.gc.newObj(.Ot_BigInt, PObj.OBigInt) catch { 269 | return PValue.makeNil(); 270 | }; 271 | 272 | if (!x.initInt(vm.gc)) return PValue.makeNil(); 273 | 274 | x.ival.sqrt(&aInt.ival) catch { 275 | return PValue.makeNil(); 276 | }; 277 | 278 | vm.stack.push(x.parent().asValue()) catch return PValue.makeNil(); 279 | 280 | return vm.stack.pop() catch return PValue.makeNil(); 281 | } 282 | 283 | pub const NameFuncNew: []const u8 = "নতুন"; 284 | pub fn big_New(vm: *Vm, argc: u8, values: []PValue) PValue { 285 | if (argc != 1) { 286 | return PValue.makeError( 287 | vm.gc, 288 | "নতুন(ক) কাজটি শুধুমাত্র একটি চলরাশি গ্রহণ করে", 289 | ).?; 290 | } 291 | 292 | const item = values[0]; 293 | 294 | if (!item.isString() and !item.isNumber()) { 295 | return PValue.makeError( 296 | vm.gc, 297 | "নতুন(ক) কাজটি শুধুমাত্র সংখ্যা কিংবা স্ট্রিং গ্রহণ করে", 298 | ).?; 299 | } 300 | const x: *PObj.OBigInt = vm.gc.newObj(.Ot_BigInt, PObj.OBigInt) catch { 301 | return PValue.makeNil(); 302 | }; 303 | 304 | _ = x.initInt(vm.gc); 305 | 306 | vm.stack.push(x.parent().asValue()) catch return PValue.makeNil(); 307 | 308 | if (item.isString()) { 309 | const rawString = item.asObj().asString(); 310 | 311 | const u8string = rawString.chars; 312 | 313 | x.ival.setString(10, u8string) catch { 314 | return PValue.makeComptimeError( 315 | vm.gc, 316 | "নতুন(...) কাজটিতে অবৈধ স্ট্রিং \"{s}\" দেওয়া হয়েছে!", 317 | .{u8string}, 318 | ).?; 319 | }; 320 | } else if (item.isNumber()) { 321 | const number = item.asNumber(); 322 | const f_temp: i64 = std.math.lossyCast(isize, @trunc(number)); 323 | x.ival.set(f_temp) catch return PValue.makeNil(); 324 | } 325 | 326 | return vm.stack.pop() catch return PValue.makeNil(); 327 | } 328 | -------------------------------------------------------------------------------- /notes/stdlib.md: -------------------------------------------------------------------------------- 1 | # Pankti Internal Memo #2 2 | 3 | ```yaml 4 | Title: Pankti Standard Library and Builtins 5 | Author: Palash Bauri 6 | 7 | Status: Draft 8 | Created: April 23, 2023 16:25:04 IST 9 | Last Modified: May 12, 2023 17:09:01 IST 10 | ``` 11 | 12 | ## Abstract 13 | This memo describes and mentions all the standard library and builtin functions 14 | which must be present in all Implementation of Pankti Programming Language 15 | 16 | ## Built-in Functions 17 | 18 | ##### type(v : Value) -> String 19 | Returns the type of `v` 20 | * Number -> `number` 21 | * Nil -> `nil` 22 | * Bool -> `bool` 23 | * String -> `string` 24 | * Module -> `module` 25 | * Error Object -> `error` 26 | * Function -> `function` 27 | * Closure - > `closure` 28 | * Array -> `array` 29 | * Native Function -> `native` 30 | * Upvalue (Closure Free Variable) -> `upvalue` 31 | * Big Number -> `bignum` 32 | * HashMap -> `map` 33 | 34 | ##### len(v : Value) -> Number 35 | 36 | Returns length (differs from type to type) 37 | 38 | Only works with `string`, `array`, and `maps` 39 | 40 | For `string`s returns the count of UTF-32 encoded characters. 41 | 42 | For `array`s returns the count of items present. 43 | 44 | For `map`s returns the count of key-value pairs. 45 | 46 | 47 | 48 | ##### asserteq(a : Value , b : Value) -> Bool 49 | 50 | Returns `true` if a == b, otherwise returns `false` 51 | 52 | ##### clock() -> Number 53 | 54 | Returns program time so far in seconds 55 | 56 | 57 | 58 | ## Standard Library 59 | ### 1. OS 60 | #### Description: 61 | Utility functions for fetching information related to the current operating 62 | system. 63 | 64 | #### Module Name: os 65 | 66 | #### Functions 67 | ##### os.**name()** -> String 68 | 69 | Returns the name of operating system presently being used. 70 | On Windows returns 'windows' 71 | On Linux based distribution and on other Unix-like OS, returns 'unix' 72 | On MacOS returns 'macos' 73 | On Android returns 'android' 74 | On Others or if failed to detect, returns 'unknown' 75 | 76 | 77 | ##### os.**arch()** -> String 78 | 79 | 80 | On x86_64 / amd64 / 64-bit systems, it returns '64'. 81 | On x86 / 32-bit systems, it returns '32'. 82 | On arm systems, it returns 'arm'. 83 | On other systems or if failed to detect, it returns 'unknown'. 84 | 85 | ##### os.**user()** -> String 86 | 87 | Returns the user name of current users 88 | 89 | ##### os.**home()** -> String 90 | Returns the home directory of the current user 91 | 92 | ##### os.**curdir()** -> String 93 | Returns current working directory 94 | 95 | ### 2. Array 96 | #### Description: 97 | Helper functions to modify and take advantage of arrays 98 | 99 | #### Module Name: array / 100 | 101 | #### Functions 102 | 103 | ##### array.**pop(input : Array)** -> Nil 104 | Removes the last element of the array `input`. Mutates the input array. Always returns nil. 105 | 106 | ##### array.**push(arr : Array , v : Value)** -> Nil 107 | Add the `v` (any type) to the end of `arr` by mutating the `arr` Array. Always returns nil 108 | 109 | ##### array.**join(a : Array , b : Array)** -> Array 110 | 111 | Returns a new Array by joining `a` and `b`. Doesn't mutate `a` or `b`. 112 | 113 | ##### array.**popat(arr : Array , index : Number)** -> Value 114 | 115 | Removes the `N`th element of `arr` where `N = index` (in Pankti first element is 0th), returns the removed element Value. 116 | 117 | `index` must be non non negative integer. 118 | 119 | ### 3. Big 120 | #### Description: 121 | Big Numbers, creating and using functions. 122 | #### Module Name: big / 123 | #### Functions 124 | 125 | ##### big.**new(v : Value)** -> Big Number 126 | 127 | Creates a new big number from `v`, which can be a number or string. When manually creating big numbers it is recommended to use strings as `v` 128 | 129 | ##### big.**add(a : Big Number , b : Big Number)** -> Big Number 130 | 131 | Returns `a+b` 132 | 133 | #### big.**sub(a : Big Number , b : Big Number)** -> Big Number 134 | 135 | Returns `a-b` 136 | 137 | ##### big.**gt(a : Big Number , b : Big Number)** -> Bool 138 | 139 | Returns `true` if `a > b` else returns `false` 140 | 141 | ##### big.**lt(a : Big Number , b : Big Number)** -> Bool 142 | 143 | Returns `true` if `a < b` else returns `false` 144 | 145 | 146 | ##### big.**eq(a : Big Number , b : Big Number)** -> Bool 147 | 148 | Returns `true` if `a == b` else returns `false` 149 | 150 | 151 | ##### big.**noteq(a : Big Number , b : Big Number)** -> Bool 152 | 153 | Returns `true` if `a != b` else returns `false` 154 | 155 | 156 | ##### big.**pi()** -> Big Number 157 | 158 | Returns the value of `Pi` as Big Number 159 | 160 | ##### big.**e()** -> Big Number 161 | 162 | Returns the value of `e` as Big Number 163 | 164 | ### 4. Common 165 | #### Description: 166 | Some common utility functions 167 | #### Module Name: common / 168 | #### Functions 169 | ##### common.**readline()** -> String 170 | Read line from Standard Input, and return the line as string. 171 | If failed to read line or failed to allocate memory for reading line, returns empty string 172 | 173 | ### 5. File 174 | #### Description: 175 | Utility functions to interact with File system 176 | #### Module Name: file / 177 | #### Functions 178 | 179 | ##### file.**exists(path : String)** -> Boolean 180 | Check if `path` exists in file system. 181 | 182 | ##### file.**readfile(path : String)** -> String 183 | Reads a file at `path` and returns the contents of the file as string. 184 | If File doesn't exist return an empty string 185 | 186 | ##### file.**isfile(path : String)** -> Boolean 187 | Check if `path` points to a file. 188 | 189 | ##### file.**isdir(path : String)** -> Boolean 190 | Check if `path` points to a directory. 191 | 192 | ##### file.**create_empty(path : String)** -> Boolean 193 | Create an empty file at `path`. Returns `true` if successful else returns `false` 194 | 195 | ##### file.**rename(old : String, new : String)** -> Boolean 196 | Renames `old` to `new`. Returns `true` if successful else returns `false` 197 | 198 | ##### file.**delete(path : String)** -> Boolean 199 | Removes `path`. Returns `true` if successful else returns `false` 200 | 201 | ##### file.**write(path : String , data : String)** -> Boolean 202 | Writes `data` to file at `path`. This function will overwrite any data already present in `path`, if `path` doesn't exist it will try to create a file there. Returns true if successful, otherwise make the program create an error and exit. 203 | 204 | ##### file.**append(path : String , data : String)** -> Boolean 205 | Writes `data` at the end of the file at `path`. This function will not overwrite any data already present in `path. Returns true if successful, otherwise make the program create an error and exit. 206 | 207 | ### 6. Map 208 | #### Description: 209 | Utility functions for Hashmaps/Hashtables 210 | #### Module Name: map / 211 | #### Functions 212 | ##### map.**iskey(m : Map , v : Value)** -> Boolean 213 | Returns true if `v` is an key of `m` hashtable, else returns `false` 214 | 215 | ##### map.**keys(m : Map)** -> Array 216 | Returns all keys of `m` as an Array 217 | 218 | ##### map.**values(m : Map)** -> Array 219 | Returns all values of `m` as an Array 220 | 221 | 222 | ### 7. String 223 | #### Description: 224 | Utility functions for Strings 225 | #### Module Name: str / 226 | #### Functions 227 | 228 | ##### str.**split(input : String , delim : String)** -> Array 229 | Splits the string `input` with `delim` as delimiter and returns the parts as an array 230 | 231 | ##### str.**string(v : Value)** -> String 232 | Returns the string form of `v` 233 | 234 | 235 | ### 8. Math 236 | #### Description: 237 | Some common Mathematics functions 238 | #### Module Name: math / 239 | #### Functions 240 | #### math.**pow(a : Number , b : Number)** -> Number 241 | $a^b$ . Returns `a`b. 242 | 243 | ##### math.**gcd(a : Number , b : Number)** -> Number 244 | $gcd(a , b)$ .Returns greatest common divisor (GCD) of `a` and `b` 245 | 246 | ##### math.**lcm(a : Number , b : Number)** -> Number 247 | $lcm(a, b)$ .Returns least common multiplier (LCM) of `a` and `b` 248 | 249 | ##### math.**sqrt(a : Number)** -> Number 250 | $\sqrt{a}$. Returns square root of a. 251 | 252 | ##### math.**log10(a : Number)** -> Number 253 | 254 | $\log_{10}(a)$ . Log a (base 10) 255 | 256 | ##### math.**loge(a : Number)** -> Number 257 | 258 | $ln(a)$ . Natural log of a 259 | 260 | ##### math.**logx( b : Number , a : Number) **-> Number 261 | 262 | $\log_{b}(a)$. Log of `a` (base `b`) 263 | 264 | ##### math.**sin(a : Number)** -> Number 265 | 266 | Sine of `a` radians 267 | 268 | ##### math.**tan(a : Number)** -> Number 269 | 270 | Tangent of `a` radians 271 | 272 | ##### math.**cos(a : Number)** -> Number 273 | 274 | Cosine of `a` radians 275 | 276 | ##### math.**degree(a : Number)** -> Number 277 | 278 | Value of `a` radians in degrees 279 | 280 | ##### math.**rad(a : Number)** -> Number 281 | 282 | Value of `a` degrees in radians 283 | 284 | ##### math.**pi()** -> Number 285 | 286 | Returns a fixed value of Pi ($\pi$) 287 | 288 | ##### math.**e()** -> Number 289 | 290 | Returns a fixed value of `e` (Euler's constant ) 291 | 292 | ##### math.**strtonum(a : String)** -> Number 293 | 294 | Try convert `a` (a must contain english digits) to a number. 295 | 296 | ##### math.**randnum()** -> Number 297 | 298 | Generates a pseudo-random decimal number within 0 to 1 299 | 300 | ##### math.**random(min : Number , max : Number)** -> Number 301 | 302 | Generates a pseudo-random decimal number within `min` to `max` 303 | 304 | ##### math.**abs(a : Number)** -> Number 305 | 306 | $|a|$. Returns absolute value of `a ` 307 | 308 | ##### math.**round(a : Number)** -> Number 309 | 310 | Returns rounded value of `a ` 311 | 312 | ##### math.**infiniy()** -> Number 313 | 314 | Returns raw `C` infinity $\infty$ 315 | 316 | ##### math.**ceil(a : Number)** -> Number 317 | 318 | Returns rounded up smallest integer greater than or equal to the value of `a` 319 | -------------------------------------------------------------------------------- /src/utils.zig: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) Palash Bauri 3 | // 4 | // This Source Code Form is subject to the terms of the Mozilla Public 5 | // License, v. 2.0. If a copy of the MPL was not distributed with this 6 | // file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | // 8 | // SPDX-License-Identifier: MPL-2.0 9 | 10 | const std = @import("std"); 11 | const builtin = @import("builtin"); 12 | const writer = @import("writer.zig"); 13 | const Gc = @import("gc.zig").Gc; 14 | const bn = @import("bengali/bn.zig"); 15 | 16 | pub extern fn getTimestamp() usize; 17 | 18 | pub fn matchU8(a: []const u8, b: []const u8) bool { 19 | return std.mem.eql(u8, a, b); 20 | } 21 | 22 | pub fn matchIdent( 23 | i: []const u8, 24 | a: []const u8, 25 | b: []const u8, 26 | c: []const u8, 27 | ) bool { 28 | if (std.mem.eql(u8, i, a) or std.mem.eql(u8, i, b) or std.mem.eql( 29 | u8, 30 | i, 31 | c, 32 | )) { 33 | return true; 34 | } 35 | return false; 36 | } 37 | 38 | pub fn isInt(v: f64) bool { 39 | return @ceil(v) == v; 40 | } 41 | 42 | pub fn asInt(v: f64) i64 { 43 | return @intFromFloat(@ceil(v)); 44 | } 45 | 46 | pub fn asUint(v: f64) u64 { 47 | return @abs(asInt(v)); 48 | } 49 | 50 | pub fn strBnToEnNum(al: std.mem.Allocator, input: []const u32, len: usize) ![]u8 { 51 | var i: usize = 0; 52 | const result = try al.alloc(u32, len); 53 | while (i < len) : (i += 1) { 54 | result[i] = bn.bnToEnNum(input[i]); 55 | } 56 | 57 | return result; 58 | } 59 | 60 | pub const UTFError = error{ 61 | InvalidUTF8ByteLength, 62 | InvalidUTF32Byte, 63 | }; 64 | 65 | pub fn getUtf32LenFor8(input: []const u8, len: usize) UTFError!usize { 66 | var result: usize = 0; 67 | var index: usize = 0; 68 | 69 | while (index < len) { 70 | const b = input[index]; 71 | const blen = std.unicode.utf8ByteSequenceLength(b) catch { 72 | return UTFError.InvalidUTF8ByteLength; 73 | }; 74 | 75 | index += blen; 76 | result += 1; 77 | } 78 | 79 | return result; 80 | } 81 | 82 | pub fn getUTF8LenFor32(input: []const u32) UTFError!usize { 83 | var result: usize = 0; 84 | 85 | for (input) |c32| { 86 | const char: u21 = @truncate(c32); 87 | result += std.unicode.utf8CodepointSequenceLength(char) catch { 88 | return UTFError.InvalidUTF32Byte; 89 | }; 90 | } 91 | 92 | return result; 93 | } 94 | 95 | /// Convert a UTF-8 encoded string to UTF-32 encoded string 96 | /// You must free the result 97 | pub fn _u8tou32(input: []const u8, alc: std.mem.Allocator) ![]u32 { 98 | const inputLen = input.len; 99 | const outLen = try getUtf32LenFor8(input, inputLen); 100 | var ustr = try alc.alloc(u32, outLen); 101 | var outindex: usize = 0; 102 | var index: usize = 0; 103 | 104 | while (index < inputLen and outindex < outLen) { 105 | const bt = input[index]; 106 | var cp: u21 = 0; 107 | const byteLen = std.unicode.utf8ByteSequenceLength(bt) catch { 108 | return UTFError.InvalidUTF8ByteLength; 109 | }; 110 | 111 | if (byteLen == 1) { 112 | cp = @intCast(bt); 113 | index += 1; 114 | } else if (byteLen == 2) { 115 | cp = try std.unicode.utf8Decode2([2]u8{ bt, input[index + 1] }); 116 | index += 2; 117 | } else if (byteLen == 3) { 118 | cp = try std.unicode.utf8Decode3([3]u8{ 119 | bt, 120 | input[index + 1], 121 | input[index + 2], 122 | }); 123 | index += 3; 124 | } else { 125 | cp = try std.unicode.utf8Decode4([4]u8{ 126 | bt, 127 | input[index + 1], 128 | input[index + 2], 129 | input[index + 3], 130 | }); 131 | } 132 | 133 | ustr[outindex] = @intCast(cp); 134 | outindex += 1; 135 | } 136 | 137 | return ustr; 138 | } 139 | 140 | /// Convert UTF-32 encoded string to UTF-8 encoded string 141 | /// You must free the result 142 | pub fn _u32tou8( 143 | input: []const u32, 144 | al: std.mem.Allocator, 145 | ) anyerror![]u8 { 146 | const u8Len = try getUTF8LenFor32(input); 147 | var u8str = try al.alloc(u8, u8Len); 148 | 149 | var i: usize = 0; 150 | 151 | for (input) |c32| { 152 | const char: u21 = @truncate(c32); 153 | 154 | const l = try std.unicode.utf8CodepointSequenceLength(char); 155 | //std.debug.print("\n{d}|L->{d}\n", .{ u8Len, l }); 156 | _ = try std.unicode.utf8Encode(char, u8str[i..]); 157 | i += l; 158 | } 159 | 160 | return u8str; 161 | } 162 | 163 | pub fn hashChars(input: []const u8, _: *Gc) !u32 { 164 | var result: u32 = 0; 165 | 166 | //if (IS_WASM) { 167 | var hasher = std.hash.Fnv1a_32.init(); 168 | hasher.update(input); 169 | result = hasher.final(); 170 | 171 | // Do we really need XxHash? 172 | 173 | //} else { 174 | // var hasher = std.hash.XxHash32.init(gc.timestamp); 175 | // const u = try u32tou8(input, gc.hal()); 176 | // hasher.update(u); 177 | // gc.hal().free(u); 178 | // result = hasher.final(); 179 | //} 180 | return result; 181 | } 182 | 183 | /// Print a UTF-32 encoded string to stdout 184 | pub fn printu32(input: []const u32, w: std.io.AnyWriter) void { 185 | for (input) |value| { 186 | w.print("{u}", .{@as(u21, @truncate(value))}) catch return; 187 | } 188 | } 189 | 190 | /// Check if `c` is valid english number 191 | pub fn isEnNum(c: u32) bool { 192 | return c <= '9' and c >= '0'; 193 | } 194 | 195 | /// Check if `c` is valid english letter or underscore `_` 196 | pub fn isValidEn(c: u32) bool { 197 | return (c >= 'a' and c <= 'z') or (c >= 'A' and c <= 'Z') or c == '_'; 198 | } 199 | 200 | /// Check if `a` is same as `b` 201 | pub fn matchU32(a: []const u32, b: []const u32) bool { 202 | if (a.len != b.len) { 203 | return false; 204 | } 205 | 206 | var i: u32 = 0; 207 | while (i < a.len) { 208 | if (a[i] != b[i]) { 209 | return false; 210 | } 211 | i += 1; 212 | } 213 | 214 | return true; 215 | } 216 | 217 | /// Convert an u16 to u8 218 | pub fn u16tou8(a: u16) [2]u8 { 219 | var result: [2]u8 = undefined; 220 | result[0] = @intCast(a >> 8); 221 | result[1] = @intCast(a & 0xff); 222 | return result; 223 | } 224 | 225 | /// Convert two u8 to u16 226 | pub fn u8tou16(a: []const u8) u16 { 227 | if (a.len > 2) { 228 | return 0; 229 | } 230 | const result: u16 = (@as(u16, @intCast(a[0])) << 8) | @as(u16, @intCast(a[1])); 231 | return result; 232 | } 233 | 234 | pub const IS_WASM = (builtin.target.cpu.arch.isWasm() and builtin.target.os.tag == .freestanding); 235 | 236 | pub const IS_WIN: bool = builtin.target.os.tag == .windows; 237 | pub const IS_MAC: bool = builtin.target.os.tag.isDarwin(); 238 | pub const IS_LINUX: bool = builtin.target.os.tag == .windows; 239 | 240 | test "test utils->u8tou32->english" { 241 | const al = std.testing.allocator; 242 | const text = "The quick brown fox jumps over the lazy dog"; 243 | 244 | const textU32 = try _u8tou32(text, al); 245 | 246 | const textU32X = [_]u32{ 247 | 84, 248 | 104, 249 | 101, 250 | 32, 251 | 113, 252 | 117, 253 | 105, 254 | 99, 255 | 107, 256 | 32, 257 | 98, 258 | 114, 259 | 111, 260 | 119, 261 | 110, 262 | 32, 263 | 102, 264 | 111, 265 | 120, 266 | 32, 267 | 106, 268 | 117, 269 | 109, 270 | 112, 271 | 115, 272 | 32, 273 | 111, 274 | 118, 275 | 101, 276 | 114, 277 | 32, 278 | 116, 279 | 104, 280 | 101, 281 | 32, 282 | 108, 283 | 97, 284 | 122, 285 | 121, 286 | 32, 287 | 100, 288 | 111, 289 | 103, 290 | }; 291 | 292 | try std.testing.expectEqual(text.len, textU32.len); 293 | try std.testing.expectEqual(textU32.len, textU32X.len); 294 | 295 | for (textU32, 0..) |value, i| { 296 | try std.testing.expectEqual(value, textU32X[i]); 297 | } 298 | 299 | al.free(textU32); 300 | } 301 | 302 | test "test utils->u8tou32->bengali" { 303 | const al = std.testing.allocator; 304 | const text = "এ বিশ্বকে এ শিশুর বাসযোগ্য করে যাব আমি\nনবজাতকের কাছে এ আমার দৃঢ় অঙ্গীকার"; 305 | const textU32 = try _u8tou32(text, al); 306 | 307 | const textU32X = [_]u32{ 308 | 0x098f, 309 | 0x0020, 310 | 0x09ac, 311 | 0x09bf, 312 | 0x09b6, 313 | 0x09cd, 314 | 0x09ac, 315 | 0x0995, 316 | 0x09c7, 317 | 0x0020, 318 | 0x098f, 319 | 0x0020, 320 | 0x09b6, 321 | 0x09bf, 322 | 0x09b6, 323 | 0x09c1, 324 | 0x09b0, 325 | 0x0020, 326 | 0x09ac, 327 | 0x09be, 328 | 0x09b8, 329 | 0x09af, 330 | 0x09cb, 331 | 0x0997, 332 | 0x09cd, 333 | 0x09af, 334 | 0x0020, 335 | 0x0995, 336 | 0x09b0, 337 | 0x09c7, 338 | 0x0020, 339 | 0x09af, 340 | 0x09be, 341 | 0x09ac, 342 | 0x0020, 343 | 0x0986, 344 | 0x09ae, 345 | 0x09bf, 346 | 0x000a, 347 | 0x09a8, 348 | 0x09ac, 349 | 0x099c, 350 | 0x09be, 351 | 0x09a4, 352 | 0x0995, 353 | 0x09c7, 354 | 0x09b0, 355 | 0x0020, 356 | 0x0995, 357 | 0x09be, 358 | 0x099b, 359 | 0x09c7, 360 | 0x0020, 361 | 0x098f, 362 | 0x0020, 363 | 0x0986, 364 | 0x09ae, 365 | 0x09be, 366 | 0x09b0, 367 | 0x0020, 368 | 0x09a6, 369 | 0x09c3, 370 | 0x09a2, 371 | 0x09bc, 372 | 0x0020, 373 | 0x0985, 374 | 0x0999, 375 | 0x09cd, 376 | 0x0997, 377 | 0x09c0, 378 | 0x0995, 379 | 0x09be, 380 | 0x09b0, 381 | }; 382 | 383 | try std.testing.expectEqual(textU32X.len, textU32.len); 384 | 385 | for (textU32, 0..) |value, i| { 386 | try std.testing.expectEqual(value, textU32X[i]); 387 | } 388 | 389 | al.free(textU32); 390 | } 391 | 392 | test "test utils->u32tou8->english" { 393 | const al = std.testing.allocator; 394 | const textU32 = [_]u32{ 395 | 84, 396 | 104, 397 | 101, 398 | 32, 399 | 113, 400 | 117, 401 | 105, 402 | 99, 403 | 107, 404 | 32, 405 | 98, 406 | 114, 407 | 111, 408 | 119, 409 | 110, 410 | 32, 411 | 102, 412 | 111, 413 | 120, 414 | 32, 415 | 106, 416 | 117, 417 | 109, 418 | 112, 419 | 115, 420 | 32, 421 | 111, 422 | 118, 423 | 101, 424 | 114, 425 | 32, 426 | 116, 427 | 104, 428 | 101, 429 | 32, 430 | 108, 431 | 97, 432 | 122, 433 | 121, 434 | 32, 435 | 100, 436 | 111, 437 | 103, 438 | }; 439 | 440 | const textU8 = try _u32tou8(&textU32, al); 441 | 442 | const text = "The quick brown fox jumps over the lazy dog"; 443 | 444 | try std.testing.expectEqual(textU8.len, textU8.len); 445 | 446 | for (textU8, 0..) |value, i| { 447 | try std.testing.expectEqual(value, text[i]); 448 | } 449 | 450 | al.free(textU8); 451 | } 452 | -------------------------------------------------------------------------------- /src/stdlib/math.zig: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) Palash Bauri 3 | // 4 | // This Source Code Form is subject to the terms of the Mozilla Public 5 | // License, v. 2.0. If a copy of the MPL was not distributed with this 6 | // file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | // 8 | // SPDX-License-Identifier: MPL-2.0 9 | 10 | const std = @import("std"); 11 | const value = @import("../value.zig"); 12 | const Vm = @import("../vm.zig").Vm; 13 | const PValue = value.PValue; 14 | const utils = @import("../utils.zig"); 15 | const stdlib = @import("stdlib.zig"); 16 | const msl = stdlib.msl; 17 | const builtin = @import("builtin"); 18 | 19 | const CONST_PI: f64 = 3.14159265358979323846; 20 | const CONST_E: f64 = 2.71828182845904523536; 21 | 22 | //গণিত 23 | pub const Name = "গণিত"; 24 | pub const NameFuncPi = "পাই"; 25 | pub fn math_Pi(vm: *Vm, argc: u8, values: []PValue) PValue { 26 | _ = values; 27 | if (argc != 0) { 28 | return PValue.makeError( 29 | vm.gc, 30 | "পাই() কাজটি মাত্র একটি চলরাশি গ্রহণ করে!", 31 | ).?; 32 | } 33 | 34 | return PValue.makeNumber(CONST_PI); 35 | } 36 | 37 | pub const NameFuncE = "ই"; 38 | pub fn math_E(vm: *Vm, argc: u8, values: []PValue) PValue { 39 | _ = values; 40 | if (argc != 0) { 41 | return PValue.makeError( 42 | vm.gc, 43 | "ই() কাজটি মাত্র একটি চলরাশি গ্রহণ করে!", 44 | ).?; 45 | } 46 | 47 | return PValue.makeNumber(CONST_E); 48 | } 49 | 50 | pub const NameFuncSqrt = "বর্গমূল"; 51 | pub fn math_Sqrt(vm: *Vm, argc: u8, values: []PValue) PValue { 52 | if (argc != 1) { 53 | return PValue.makeError( 54 | vm.gc, 55 | "বর্গমূল() কাজটি মাত্র একটি চলরাশি গ্রহণ করে!", 56 | ).?; 57 | } 58 | 59 | const rawValue = values[0]; 60 | if (!rawValue.isNumber()) { 61 | return PValue.makeError( 62 | vm.gc, 63 | "গণিতের বর্গমূল(ক) কাজটি শুধু সংখ্যা মান গ্রহণ করে", 64 | ).?; 65 | } 66 | 67 | return PValue.makeNumber(std.math.sqrt(rawValue.asNumber())); 68 | } 69 | 70 | pub const NameFuncLog10 = "লগদশ"; 71 | pub fn math_Log10(vm: *Vm, argc: u8, values: []PValue) PValue { 72 | if (argc != 1) { 73 | return PValue.makeError( 74 | vm.gc, 75 | "লগদশ() কাজটি শুধু একটি চলরাশি গ্রহণ", 76 | ).?; 77 | } 78 | 79 | const rawValue = values[0]; 80 | if (!rawValue.isNumber()) { 81 | return PValue.makeError( 82 | vm.gc, 83 | "গণিতের লগদশ(ক) কাজটি শুধু সংখ্যা মান গ্রহণ করে", 84 | ).?; 85 | } 86 | 87 | return PValue.makeNumber(std.math.log10(rawValue.asNumber())); 88 | } 89 | 90 | pub const NameFuncLog = "লগ"; 91 | pub fn math_Log(vm: *Vm, argc: u8, values: []PValue) PValue { 92 | if (argc != 1) { 93 | return PValue.makeError( 94 | vm.gc, 95 | "লগ() কাজটি শুধু একটি চলরাশি গ্রহণ", 96 | ).?; 97 | } 98 | 99 | const rawValue = values[0]; 100 | if (!rawValue.isNumber()) { 101 | return PValue.makeError( 102 | vm.gc, 103 | "গণিতের লগ(ক) কাজটি শুধু সংখ্যা মান গ্রহণ করে", 104 | ).?; 105 | } 106 | 107 | return PValue.makeNumber(@log(rawValue.asNumber())); 108 | } 109 | 110 | pub const NameFuncLogX = "লগবেস"; 111 | pub fn math_LogX(vm: *Vm, argc: u8, values: []PValue) PValue { 112 | if (argc != 2) { 113 | return PValue.makeError( 114 | vm.gc, 115 | "দগদশ() কাজটি শুধু দুটি চলরাশি গ্রহণ করে", 116 | ).?; 117 | } 118 | 119 | if (!values[0].isNumber() or !values[1].isNumber()) { 120 | return PValue.makeError( 121 | vm.gc, 122 | "গণিতের লগবেস(ক , খ) কাজটি শুধু সংখ্যা মান গ্রহণ করে", 123 | ).?; 124 | } 125 | 126 | const rawBase = values[0].asNumber(); 127 | const rawNum = values[1].asNumber(); 128 | 129 | return PValue.makeNumber(std.math.log(f64, rawBase, rawNum)); 130 | } 131 | 132 | pub fn getGcd(a: f64, b: f64) f64 { 133 | var x = if (a > 0) a else -a; 134 | var y = if (b > 0) b else -b; 135 | 136 | while (x != y) { 137 | if (x > y) { 138 | x -= y; 139 | } else { 140 | y -= x; 141 | } 142 | } 143 | 144 | return x; 145 | } 146 | 147 | pub const NameFuncGcd = "গসাগু"; 148 | pub fn math_Gcd(vm: *Vm, argc: u8, values: []PValue) PValue { 149 | if (argc != 2) { 150 | return PValue.makeError( 151 | vm.gc, 152 | "গসাগু() দুটি মাত্র চলরাশি গ্রহণ করে।", 153 | ).?; 154 | } 155 | 156 | if (!values[0].isNumber() or !values[1].isNumber()) { 157 | return PValue.makeError( 158 | vm.gc, 159 | "গণিতের গসাগু(ক , খ) কাজটি শুধু সংখ্যা মান গ্রহণ করে", 160 | ).?; 161 | } 162 | 163 | return PValue.makeNumber(getGcd( 164 | values[0].asNumber(), 165 | values[1].asNumber(), 166 | )); 167 | } 168 | 169 | pub const NameFuncLcm = "লসাগু"; 170 | pub fn math_Lcm(vm: *Vm, argc: u8, values: []PValue) PValue { 171 | if (argc != 2) { 172 | return PValue.makeError( 173 | vm.gc, 174 | "গণিতের লসাগু(ক , খ) কাজটি শুধু দুটি মান গ্রহণ করে", 175 | ).?; 176 | } 177 | 178 | if (!values[0].isNumber() or !values[1].isNumber()) { 179 | return PValue.makeError( 180 | vm.gc, 181 | "গণিতের লসাগু(ক , খ) কাজটি শুধু সংখ্যা মান গ্রহণ করে", 182 | ).?; 183 | } 184 | 185 | const a = values[0].asNumber(); 186 | const b = values[1].asNumber(); 187 | 188 | return PValue.makeNumber((a * b) / getGcd(a, b)); 189 | } 190 | 191 | pub const NameFuncSine = "সাইন"; 192 | pub fn math_Sine(vm: *Vm, argc: u8, values: []PValue) PValue { 193 | if (argc != 1) { 194 | return PValue.makeError( 195 | vm.gc, 196 | "সাইন(ক) কাজটি শুধু একটি মান গ্রহণ করে", 197 | ).?; 198 | } 199 | 200 | if (!values[0].isNumber()) { 201 | return PValue.makeError( 202 | vm.gc, 203 | "গণিতের সাইন(ক) কাজটি শুধু সংখ্যা মান গ্রহণ করে", 204 | ).?; 205 | } 206 | 207 | return PValue.makeNumber(std.math.sin(values[0].asNumber())); 208 | } 209 | 210 | pub const NameFuncCosine = "কস"; 211 | pub fn math_Cosine(vm: *Vm, argc: u8, values: []PValue) PValue { 212 | if (argc != 1) { 213 | return PValue.makeError( 214 | vm.gc, 215 | "কস(ক) কাজটি শুধু একটি মান গ্রহণ করে ", 216 | ).?; 217 | } 218 | 219 | if (!values[0].isNumber()) { 220 | return PValue.makeError( 221 | vm.gc, 222 | "গণিতের কস(ক) কাজটি শুধু সংখ্যা মান গ্রহণ করে", 223 | ).?; 224 | } 225 | 226 | return PValue.makeNumber(std.math.cos(values[0].asNumber())); 227 | } 228 | 229 | pub const NameFuncTangent = "ট্যান"; 230 | pub fn math_Tangent(vm: *Vm, argc: u8, values: []PValue) PValue { 231 | if (argc != 1) { 232 | return PValue.makeError( 233 | vm.gc, 234 | "ট্যান(ক) কাজটি শুধু একটি মান গ্রহণ করে", 235 | ).?; 236 | } 237 | 238 | if (!values[0].isNumber()) { 239 | return PValue.makeError( 240 | vm.gc, 241 | "গণিতের ট্যান(ক) কাজটি শুধু সংখ্যা মান গ্রহণ করে", 242 | ).?; 243 | } 244 | 245 | return PValue.makeNumber(std.math.tan(values[0].asNumber())); 246 | } 247 | 248 | pub const NameFuncDegree = "ডিগ্রি"; 249 | pub fn math_Degree(vm: *Vm, argc: u8, values: []PValue) PValue { 250 | if (argc != 1) { 251 | return PValue.makeError( 252 | vm.gc, 253 | "ডিগ্রি(ক) কাজটি শুধু একটি মান গ্রহণ করে", 254 | ).?; 255 | } 256 | 257 | if (!values[0].isNumber()) { 258 | return PValue.makeError( 259 | vm.gc, 260 | "গণিতের ডিগ্রি(ক) কাজটি শুধু সংখ্যা মান গ্রহণ করে", 261 | ).?; 262 | } 263 | 264 | return PValue.makeNumber(values[0].asNumber() * (180 / CONST_PI)); 265 | } 266 | 267 | pub const NameFuncRadians = "রেডিয়ান"; 268 | pub fn math_Radians(vm: *Vm, argc: u8, values: []PValue) PValue { 269 | if (argc != 1) { 270 | return PValue.makeError( 271 | vm.gc, 272 | "রেডিয়ান(ক) কাজটি শুধু একটি মান গ্রহণ করে", 273 | ).?; 274 | } 275 | 276 | if (!values[0].isNumber()) { 277 | return PValue.makeError( 278 | vm.gc, 279 | "গণিতের রেডিয়ান(ক) কাজটি শুধু সংখ্যা মান গ্রহণ করে", 280 | ).?; 281 | } 282 | 283 | return PValue.makeNumber(values[0].asNumber() * (CONST_PI / 180)); 284 | } 285 | 286 | pub const NameFuncNumber = "সংখ্যা"; 287 | pub fn math_Number(vm: *Vm, argc: u8, values: []PValue) PValue { 288 | if (argc != 1) { 289 | return PValue.makeError( 290 | vm.gc, 291 | "সংখ্যা(ক) কাজটি শুধু একটি মান গ্রহণ করে", 292 | ).?; 293 | } 294 | 295 | if (!values[0].isString()) { 296 | return PValue.makeError( 297 | vm.gc, 298 | "গণিতের সংখ্যা(ক) কাজটি শুধুমাত্র স্ট্রিং/নাম মান গ্রহণ করে", 299 | ).?; 300 | } 301 | 302 | // const stringU8 = utils.u32tou8( 303 | // values[0].asObj().asString().chars, 304 | // vm.gc.hal(), 305 | // ) catch return PValue.makeNumber(0); 306 | const stringU8 = values[0].asObj().asString().chars; 307 | const rawNum: f64 = std.fmt.parseFloat(f64, stringU8) catch 0; 308 | 309 | const result = PValue.makeNumber(rawNum); 310 | 311 | //vm.gc.hal().free(stringU8); 312 | 313 | return result; 314 | } 315 | 316 | pub const NameFuncAbs = "পরম"; 317 | pub fn math_Abs(vm: *Vm, argc: u8, values: []PValue) PValue { 318 | if (argc != 1) { 319 | return PValue.makeError( 320 | vm.gc, 321 | "পরম(ক) কাজটি একটি মান গ্রহণ করে", 322 | ).?; 323 | } 324 | 325 | if (!values[0].isNumber()) { 326 | return PValue.makeError( 327 | vm.gc, 328 | "গণিতের পরম(ক) কাজটি শুধু সংখ্যা মান গ্রহণ করে", 329 | ).?; 330 | } 331 | 332 | return PValue.makeNumber(@abs(values[0].asNumber())); 333 | } 334 | 335 | pub const NameFuncRound = "রাউন্ড"; 336 | pub fn math_Round(vm: *Vm, argc: u8, values: []PValue) PValue { 337 | if (argc != 1) { 338 | return PValue.makeError( 339 | vm.gc, 340 | "রাউন্ড(ক) কাজটি শুধু একটি মান গ্রহণ করে", 341 | ).?; 342 | } 343 | 344 | if (!values[0].isNumber()) { 345 | return PValue.makeError( 346 | vm.gc, 347 | "গণিতের রাউন্ড(ক) কাজটি শুধু সংখ্যা মান গ্রহণ করে", 348 | ).?; 349 | } 350 | 351 | return PValue.makeNumber(std.math.round(values[0].asNumber())); 352 | } 353 | 354 | pub const NameFuncFloor = "ফ্লোর"; 355 | pub fn math_Floor(vm: *Vm, argc: u8, values: []PValue) PValue { 356 | if (argc != 1) { 357 | return PValue.makeError( 358 | vm.gc, 359 | "ফ্লোর(ক) কাজটি একটি মান গ্রহণ করে", 360 | ).?; 361 | } 362 | 363 | if (!values[0].isNumber()) { 364 | return PValue.makeError( 365 | vm.gc, 366 | "গণিতের ফ্লোর(ক) কাজটি শুধু সংখ্যা মান গ্রহণ করে", 367 | ).?; 368 | } 369 | 370 | return PValue.makeNumber(std.math.floor(values[0].asNumber())); 371 | } 372 | 373 | pub const NameFuncCeil = "সিল"; 374 | pub fn math_Ceil(vm: *Vm, argc: u8, values: []PValue) PValue { 375 | if (argc != 1) { 376 | return PValue.makeError( 377 | vm.gc, 378 | "সিল(ক) কাজটি একটি মান গ্রহণ করে", 379 | ).?; 380 | } 381 | 382 | if (!values[0].isNumber()) { 383 | return PValue.makeError( 384 | vm.gc, 385 | "গণিতের সিল(ক) কাজটি শুধু সংখ্যা মান গ্রহণ করে", 386 | ).?; 387 | } 388 | 389 | return PValue.makeNumber(std.math.ceil(values[0].asNumber())); 390 | } 391 | -------------------------------------------------------------------------------- /src/instruction.zig: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) Palash Bauri 3 | // 4 | // This Source Code Form is subject to the terms of the Mozilla Public 5 | // License, v. 2.0. If a copy of the MPL was not distributed with this 6 | // file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | // 8 | // SPDX-License-Identifier: MPL-2.0 9 | 10 | const std = @import("std"); 11 | const PValue = @import("value.zig").PValue; 12 | const Gc = @import("gc.zig").Gc; 13 | const utils = @import("utils.zig"); 14 | const PObj = @import("object.zig").PObj; 15 | const Allocator = std.mem.Allocator; 16 | 17 | pub const OpCode = enum(u8) { 18 | Op_Return, 19 | Op_Const, 20 | Op_Neg, 21 | Op_Add, 22 | Op_Sub, 23 | Op_Mul, 24 | Op_Div, 25 | Op_Mod, 26 | Op_Nil, 27 | Op_True, 28 | Op_False, 29 | Op_Not, 30 | Op_Eq, 31 | Op_Gt, 32 | Op_Gte, 33 | Op_Lt, 34 | Op_Lte, 35 | Op_Pop, 36 | Op_DefGlob, 37 | Op_SetGlob, 38 | Op_GetGlob, 39 | Op_GetLocal, 40 | Op_SetLocal, 41 | Op_JumpIfFalse, 42 | Op_Jump, 43 | Op_Loop, 44 | Op_Call, 45 | Op_Closure, 46 | Op_GetUp, 47 | Op_SetUp, 48 | Op_ClsUp, 49 | Op_Import, 50 | Op_SetModProp, 51 | Op_GetModProp, 52 | Op_EndMod, 53 | Op_Err, 54 | Op_Array, 55 | Op_Hmap, 56 | Op_Index, 57 | Op_SubAssign, 58 | 59 | Op_Show, 60 | Op_Neq, 61 | Op_Pow, 62 | 63 | const Self = @This(); 64 | pub fn toString(self: *const Self) []const u8 { 65 | return switch (self.*) { 66 | .Op_Return => "OP_RETURN", 67 | .Op_Const => "OP_CONST", 68 | .Op_Neg => "OP_NEG", 69 | .Op_Add => "OP_ADD", 70 | .Op_Sub => "OP_SUB", 71 | .Op_Mul => "OP_MUL", 72 | .Op_Pow => "OP_POW", 73 | .Op_Div => "OP_DIV", 74 | .Op_Mod => "OP_MOD", 75 | .Op_Nil => "OP_NIL", 76 | .Op_True => "OP_TRUE", 77 | .Op_False => "OP_FALSE", 78 | .Op_Not => "OP_NOT", 79 | .Op_Eq => "OP_EQ", 80 | .Op_Neq => "OP_NEQ", 81 | .Op_Gt => "OP_GT", 82 | .Op_Gte => "OP_GTE", 83 | .Op_Lt => "OP_LT", 84 | .Op_Lte => "OP_LTE", 85 | .Op_Show => "OP_SHOW", 86 | .Op_Pop => "OP_POP", 87 | .Op_DefGlob => "OP_DEF_GLOB", 88 | .Op_SetGlob => "OP_SET_GLOB", 89 | .Op_GetGlob => "OP_GET_GLOB", 90 | .Op_GetLocal => "OP_GET_LOCAL", 91 | .Op_SetLocal => "OP_SET_LOCAL", 92 | .Op_JumpIfFalse => "OP_JUMP_IF_FALSE", 93 | .Op_Jump => "OP_JUMP", 94 | .Op_Loop => "OP_LOOP", 95 | .Op_Call => "OP_CALL", 96 | .Op_Closure => "OP_CLOSURE", 97 | .Op_GetUp => "OP_GET_UP", 98 | .Op_SetUp => "OP_SET_UP", 99 | .Op_ClsUp => "OP_CLOSE_UP", 100 | .Op_Import => "OP_IMPORT", 101 | .Op_SetModProp => "OP_SET_MOD_PROP", 102 | .Op_GetModProp => "OP_GET_MOD_PROP", 103 | .Op_EndMod => "OP_END_MOD", 104 | .Op_Err => "OP_ERR", 105 | .Op_Array => "OP_ARRAY", 106 | .Op_Hmap => "OP_HMAP", 107 | .Op_Index => "OP_INDEX", 108 | .Op_SubAssign => "OP_SUB_ASSIGN", 109 | //else => {"OP_UNKNOWN"; } 110 | }; 111 | } 112 | }; 113 | 114 | pub const InstPos = struct { 115 | virtual: bool, 116 | colpos: u32, 117 | line: usize, 118 | length: u32, 119 | 120 | pub fn dummy() InstPos { 121 | return InstPos{ 122 | .virtual = true, 123 | .colpos = 0, 124 | .line = 0, 125 | .length = 0, 126 | }; 127 | } 128 | 129 | pub fn lined(l: usize) InstPos { 130 | return InstPos{ 131 | .virtual = true, 132 | .colpos = 0, 133 | .line = l, 134 | .length = 0, 135 | }; 136 | } 137 | }; 138 | 139 | pub const Instruction = struct { 140 | code: std.ArrayListUnmanaged(u8), 141 | pos: std.ArrayListUnmanaged(InstPos), 142 | cons: std.ArrayListUnmanaged(PValue), 143 | gc: *Gc, 144 | 145 | pub fn init(gc: *Gc) Instruction { 146 | return Instruction{ 147 | .code = std.ArrayListUnmanaged(u8){}, 148 | .pos = std.ArrayListUnmanaged(InstPos){}, 149 | .cons = std.ArrayListUnmanaged(PValue){}, 150 | .gc = gc, 151 | }; 152 | } 153 | 154 | pub fn makeChangesForModule(self: *Instruction) bool { 155 | const len = self.code.items.len; 156 | if (len < 2) return false; 157 | self.code.items[len - 1] = @intFromEnum(OpCode.Op_EndMod); 158 | return true; 159 | } 160 | 161 | pub fn free(self: *Instruction) void { 162 | self.code.deinit(self.gc.hal()); 163 | self.pos.deinit(self.gc.hal()); 164 | self.cons.deinit(self.gc.hal()); 165 | } 166 | 167 | pub fn write_raw( 168 | self: *Instruction, 169 | bt: u8, 170 | pos: InstPos, 171 | ) Allocator.Error!void { 172 | try self.code.append(self.gc.hal(), bt); 173 | try self.pos.append(self.gc.hal(), pos); 174 | } 175 | 176 | pub fn write( 177 | self: *Instruction, 178 | bt: OpCode, 179 | pos: InstPos, 180 | ) Allocator.Error!void { 181 | try self.code.append(self.gc.hal(), @intFromEnum(bt)); 182 | try self.pos.append(self.gc.hal(), pos); 183 | } 184 | 185 | pub fn addConst( 186 | self: *Instruction, 187 | value: PValue, 188 | ) Allocator.Error!u8 { 189 | try self.cons.append(self.gc.hal(), value); 190 | return @intCast(self.cons.items.len - 1); 191 | // catch return false; 192 | //return true; 193 | } 194 | 195 | /// Return OpCode at offset 196 | fn getOpCode(self: *Instruction, offset: usize) OpCode { 197 | return @enumFromInt(self.code.items[offset]); 198 | } 199 | 200 | /// Return OpCode at offset 201 | fn getRawOpCode(self: *Instruction, offset: usize) u8 { 202 | return self.code.items[offset]; 203 | } 204 | 205 | pub fn disasm(self: *Instruction, name: []const u8) void { 206 | self.gc.pstdout.print("== {s} | [{any}] ==", .{ 207 | name, 208 | self.code.items.len, 209 | }) catch return; 210 | self.gc.pstdout.print("\n", .{}) catch return; 211 | 212 | var i: usize = 0; 213 | while (i < self.code.items.len) { 214 | i = self.disasmInstruction(i); 215 | } 216 | 217 | self.gc.pstdout.print("\n", .{}) catch return; 218 | } 219 | 220 | fn simpleInstruction( 221 | self: *Instruction, 222 | name: []const u8, 223 | offset: usize, 224 | ) usize { 225 | self.gc.pstdout.print("{s}\n", .{name}) catch return 0; 226 | return offset + 1; 227 | } 228 | 229 | fn constInstruction( 230 | self: *Instruction, 231 | name: []const u8, 232 | offset: usize, 233 | ) usize { 234 | const constIndex = self.getRawOpCode(offset + 1); 235 | self.gc.pstdout.print("{s} {d} '", .{ 236 | name, 237 | constIndex, 238 | }) catch return 0; 239 | _ = self.cons.items[constIndex].printVal(self.gc); 240 | self.gc.pstdout.print("'\n", .{}) catch return 0; 241 | 242 | return offset + 2; 243 | } 244 | 245 | fn jumpInstruction( 246 | self: *Instruction, 247 | name: []const u8, 248 | sign: i32, 249 | offset: usize, 250 | ) usize { 251 | const jump: u16 = utils.u8tou16(&[_]u8{ 252 | self.code.items[offset + 1], 253 | self.code.items[offset + 2], 254 | }); 255 | self.gc.pstdout.print("{s} {d} -> {d}\n", .{ 256 | name, 257 | offset, 258 | @as(i64, @intCast(offset)) + 3 + sign * jump, 259 | }) catch return 0; 260 | return offset + 3; 261 | } 262 | 263 | fn byteInstruction( 264 | self: *Instruction, 265 | name: []const u8, 266 | offset: usize, 267 | ) usize { 268 | const slot = self.code.items[offset + 1]; 269 | self.gc.pstdout.print("{s} {:>4}\n", .{ name, slot }) catch return 0; 270 | return offset + 2; 271 | } 272 | 273 | fn disasmInstruction(self: *Instruction, offset: usize) usize { 274 | self.gc.pstdout.print("{:0>4} ", .{offset}) catch return 0; 275 | if (offset > 0 and self.pos.items[offset].line == self.pos.items[offset - 1].line) { 276 | self.gc.pstdout.print(" | ", .{}) catch return 0; 277 | } else { 278 | self.gc.pstdout.print("{:>4} ", .{self.pos.items[offset].line}) catch return 0; 279 | } 280 | 281 | const ins = self.getOpCode(offset); 282 | 283 | switch (ins) { 284 | .Op_Return, 285 | .Op_Neg, 286 | .Op_Add, 287 | .Op_Sub, 288 | .Op_Mul, 289 | .Op_Pow, 290 | .Op_Div, 291 | .Op_Mod, 292 | .Op_Nil, 293 | .Op_True, 294 | .Op_False, 295 | .Op_Not, 296 | .Op_Eq, 297 | .Op_Neq, 298 | .Op_Lt, 299 | .Op_Gt, 300 | .Op_Pop, 301 | .Op_ClsUp, 302 | .Op_Err, 303 | .Op_Index, 304 | .Op_Show, 305 | .Op_SubAssign, 306 | => { 307 | return self.simpleInstruction(ins.toString(), offset); 308 | }, 309 | 310 | .Op_SetUp, .Op_GetUp, .Op_GetLocal, .Op_SetLocal => { 311 | return self.byteInstruction(ins.toString(), offset); 312 | }, 313 | 314 | .Op_JumpIfFalse, .Op_Jump => { 315 | return self.jumpInstruction(ins.toString(), 1, offset); 316 | }, 317 | 318 | .Op_Loop => { 319 | return self.jumpInstruction(ins.toString(), -1, offset); 320 | }, 321 | 322 | .Op_Call => { 323 | return self.byteInstruction(ins.toString(), offset); 324 | }, 325 | 326 | .Op_Const, 327 | .Op_Import, 328 | .Op_DefGlob, 329 | .Op_GetGlob, 330 | .Op_SetGlob, 331 | .Op_GetModProp, 332 | => { 333 | return self.constInstruction(ins.toString(), offset); 334 | }, 335 | 336 | .Op_Array, .Op_Hmap => { 337 | const con1 = self.code.items[offset + 1]; 338 | const con2 = self.code.items[offset + 2]; 339 | self.gc.pstdout.print("{s} {d}\n", .{ ins.toString(), utils.u8tou16(&[_]u8{ con1, con2 }) }) catch return 0; 340 | return offset + 3; 341 | }, 342 | 343 | .Op_Closure => { 344 | var off = offset + 1; 345 | const con = self.code.items[off]; 346 | off += 1; 347 | self.gc.pstdout.print("{s} {d} ", .{ ins.toString(), con }) catch return 0; 348 | _ = self.cons.items[con].printVal(self.gc); 349 | self.gc.pstdout.print("\n", .{}) catch return 0; 350 | 351 | const f: *PObj.OFunction = 352 | self.cons.items[con].asObj().asFunc(); 353 | var i: usize = 0; 354 | while (i < f.upvCount) : (i += 1) { 355 | const isLocal = self.code.items[off]; 356 | off += 1; 357 | const index = self.code.items[off]; 358 | off += 1; 359 | self.gc.pstdout.print("{:0>4} | ->", .{off - 2}) catch return 0; 360 | if (isLocal == 1) { 361 | self.gc.pstdout.print("local", .{}) catch return 0; 362 | } else { 363 | self.gc.pstdout.print("upvalue", .{}) catch return 0; 364 | } 365 | 366 | self.gc.pstdout.print(" {d}\n", .{index}) catch return 0; 367 | } 368 | 369 | return off; 370 | }, 371 | else => { 372 | return offset + 1; 373 | }, 374 | } 375 | } 376 | }; 377 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | zig-cache/ 2 | .zig-cache/ 3 | zig-out/ 4 | dist/ 5 | 6 | 7 | .ccls-cache/ 8 | 9 | neopank.perf 10 | perf.data 11 | perf.data.old 12 | *.wasm 13 | 14 | ## Ignore Visual Studio temporary files, build results, and 15 | ## files generated by popular Visual Studio add-ons. 16 | ## 17 | ## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore 18 | 19 | # User-specific files 20 | *.rsuser 21 | *.suo 22 | *.user 23 | *.userosscache 24 | *.sln.docstates 25 | 26 | # User-specific files (MonoDevelop/Xamarin Studio) 27 | *.userprefs 28 | 29 | # Mono auto generated files 30 | mono_crash.* 31 | 32 | # Build results 33 | [Dd]ebug/ 34 | [Dd]ebugPublic/ 35 | [Rr]elease/ 36 | [Rr]eleases/ 37 | x64/ 38 | x86/ 39 | [Ww][Ii][Nn]32/ 40 | [Aa][Rr][Mm]/ 41 | [Aa][Rr][Mm]64/ 42 | bld/ 43 | [Bb]in/ 44 | [Oo]bj/ 45 | [Ll]og/ 46 | [Ll]ogs/ 47 | 48 | # Visual Studio 2015/2017 cache/options directory 49 | .vs/ 50 | # Uncomment if you have tasks that create the project's static files in wwwroot 51 | #wwwroot/ 52 | 53 | # Visual Studio 2017 auto generated files 54 | Generated\ Files/ 55 | 56 | # MSTest test Results 57 | [Tt]est[Rr]esult*/ 58 | [Bb]uild[Ll]og.* 59 | 60 | # NUnit 61 | *.VisualState.xml 62 | TestResult.xml 63 | nunit-*.xml 64 | 65 | # Build Results of an ATL Project 66 | [Dd]ebugPS/ 67 | [Rr]eleasePS/ 68 | dlldata.c 69 | 70 | # Benchmark Results 71 | BenchmarkDotNet.Artifacts/ 72 | 73 | # .NET Core 74 | project.lock.json 75 | project.fragment.lock.json 76 | artifacts/ 77 | 78 | # ASP.NET Scaffolding 79 | ScaffoldingReadMe.txt 80 | 81 | # StyleCop 82 | StyleCopReport.xml 83 | 84 | # Files built by Visual Studio 85 | *_i.c 86 | *_p.c 87 | *_h.h 88 | *.ilk 89 | *.meta 90 | *.obj 91 | *.iobj 92 | *.pch 93 | *.pdb 94 | *.ipdb 95 | *.pgc 96 | *.pgd 97 | *.rsp 98 | *.sbr 99 | *.tlb 100 | *.tli 101 | *.tlh 102 | *.tmp 103 | *.tmp_proj 104 | *_wpftmp.csproj 105 | *.log 106 | *.tlog 107 | *.vspscc 108 | *.vssscc 109 | .builds 110 | *.pidb 111 | *.svclog 112 | *.scc 113 | 114 | # Chutzpah Test files 115 | _Chutzpah* 116 | 117 | # Visual C++ cache files 118 | ipch/ 119 | *.aps 120 | *.ncb 121 | *.opendb 122 | *.opensdf 123 | *.sdf 124 | *.cachefile 125 | *.VC.db 126 | *.VC.VC.opendb 127 | 128 | # Visual Studio profiler 129 | *.psess 130 | *.vsp 131 | *.vspx 132 | *.sap 133 | 134 | # Visual Studio Trace Files 135 | *.e2e 136 | 137 | # TFS 2012 Local Workspace 138 | $tf/ 139 | 140 | # Guidance Automation Toolkit 141 | *.gpState 142 | 143 | # ReSharper is a .NET coding add-in 144 | _ReSharper*/ 145 | *.[Rr]e[Ss]harper 146 | *.DotSettings.user 147 | 148 | # TeamCity is a build add-in 149 | _TeamCity* 150 | 151 | # DotCover is a Code Coverage Tool 152 | *.dotCover 153 | 154 | # AxoCover is a Code Coverage Tool 155 | .axoCover/* 156 | !.axoCover/settings.json 157 | 158 | # Coverlet is a free, cross platform Code Coverage Tool 159 | coverage*.json 160 | coverage*.xml 161 | coverage*.info 162 | 163 | # Visual Studio code coverage results 164 | *.coverage 165 | *.coveragexml 166 | 167 | # NCrunch 168 | _NCrunch_* 169 | .*crunch*.local.xml 170 | nCrunchTemp_* 171 | 172 | # MightyMoose 173 | *.mm.* 174 | AutoTest.Net/ 175 | 176 | # Web workbench (sass) 177 | .sass-cache/ 178 | 179 | # Installshield output folder 180 | [Ee]xpress/ 181 | 182 | # DocProject is a documentation generator add-in 183 | DocProject/buildhelp/ 184 | DocProject/Help/*.HxT 185 | DocProject/Help/*.HxC 186 | DocProject/Help/*.hhc 187 | DocProject/Help/*.hhk 188 | DocProject/Help/*.hhp 189 | DocProject/Help/Html2 190 | DocProject/Help/html 191 | 192 | # Click-Once directory 193 | publish/ 194 | 195 | # Publish Web Output 196 | *.[Pp]ublish.xml 197 | *.azurePubxml 198 | # Note: Comment the next line if you want to checkin your web deploy settings, 199 | # but database connection strings (with potential passwords) will be unencrypted 200 | *.pubxml 201 | *.publishproj 202 | 203 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 204 | # checkin your Azure Web App publish settings, but sensitive information contained 205 | # in these scripts will be unencrypted 206 | PublishScripts/ 207 | 208 | # NuGet Packages 209 | *.nupkg 210 | # NuGet Symbol Packages 211 | *.snupkg 212 | # The packages folder can be ignored because of Package Restore 213 | **/[Pp]ackages/* 214 | # except build/, which is used as an MSBuild target. 215 | !**/[Pp]ackages/build/ 216 | # Uncomment if necessary however generally it will be regenerated when needed 217 | #!**/[Pp]ackages/repositories.config 218 | # NuGet v3's project.json files produces more ignorable files 219 | *.nuget.props 220 | *.nuget.targets 221 | 222 | # Microsoft Azure Build Output 223 | csx/ 224 | *.build.csdef 225 | 226 | # Microsoft Azure Emulator 227 | ecf/ 228 | rcf/ 229 | 230 | # Windows Store app package directories and files 231 | AppPackages/ 232 | BundleArtifacts/ 233 | Package.StoreAssociation.xml 234 | _pkginfo.txt 235 | *.appx 236 | *.appxbundle 237 | *.appxupload 238 | 239 | # Visual Studio cache files 240 | # files ending in .cache can be ignored 241 | *.[Cc]ache 242 | # but keep track of directories ending in .cache 243 | !?*.[Cc]ache/ 244 | 245 | # Others 246 | ClientBin/ 247 | ~$* 248 | *~ 249 | *.dbmdl 250 | *.dbproj.schemaview 251 | *.jfm 252 | *.pfx 253 | *.publishsettings 254 | orleans.codegen.cs 255 | 256 | # Including strong name files can present a security risk 257 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 258 | #*.snk 259 | 260 | # Since there are multiple workflows, uncomment next line to ignore bower_components 261 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 262 | #bower_components/ 263 | 264 | # RIA/Silverlight projects 265 | Generated_Code/ 266 | 267 | # Backup & report files from converting an old project file 268 | # to a newer Visual Studio version. Backup files are not needed, 269 | # because we have git ;-) 270 | _UpgradeReport_Files/ 271 | Backup*/ 272 | UpgradeLog*.XML 273 | UpgradeLog*.htm 274 | ServiceFabricBackup/ 275 | *.rptproj.bak 276 | 277 | # SQL Server files 278 | *.mdf 279 | *.ldf 280 | *.ndf 281 | 282 | # Business Intelligence projects 283 | *.rdl.data 284 | *.bim.layout 285 | *.bim_*.settings 286 | *.rptproj.rsuser 287 | *- [Bb]ackup.rdl 288 | *- [Bb]ackup ([0-9]).rdl 289 | *- [Bb]ackup ([0-9][0-9]).rdl 290 | 291 | # Microsoft Fakes 292 | FakesAssemblies/ 293 | 294 | # GhostDoc plugin setting file 295 | *.GhostDoc.xml 296 | 297 | # Node.js Tools for Visual Studio 298 | .ntvs_analysis.dat 299 | node_modules/ 300 | 301 | # Visual Studio 6 build log 302 | *.plg 303 | 304 | # Visual Studio 6 workspace options file 305 | *.opt 306 | 307 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 308 | *.vbw 309 | 310 | # Visual Studio 6 auto-generated project file (contains which files were open etc.) 311 | *.vbp 312 | 313 | # Visual Studio 6 workspace and project file (working project files containing files to include in project) 314 | *.dsw 315 | *.dsp 316 | 317 | # Visual Studio 6 technical files 318 | *.ncb 319 | *.aps 320 | 321 | # Visual Studio LightSwitch build output 322 | **/*.HTMLClient/GeneratedArtifacts 323 | **/*.DesktopClient/GeneratedArtifacts 324 | **/*.DesktopClient/ModelManifest.xml 325 | **/*.Server/GeneratedArtifacts 326 | **/*.Server/ModelManifest.xml 327 | _Pvt_Extensions 328 | 329 | # Paket dependency manager 330 | .paket/paket.exe 331 | paket-files/ 332 | 333 | # FAKE - F# Make 334 | .fake/ 335 | 336 | # CodeRush personal settings 337 | .cr/personal 338 | 339 | # Python Tools for Visual Studio (PTVS) 340 | __pycache__/ 341 | *.pyc 342 | 343 | # Cake - Uncomment if you are using it 344 | # tools/** 345 | # !tools/packages.config 346 | 347 | # Tabs Studio 348 | *.tss 349 | 350 | # Telerik's JustMock configuration file 351 | *.jmconfig 352 | 353 | # BizTalk build output 354 | *.btp.cs 355 | *.btm.cs 356 | *.odx.cs 357 | *.xsd.cs 358 | 359 | # OpenCover UI analysis results 360 | OpenCover/ 361 | 362 | # Azure Stream Analytics local run output 363 | ASALocalRun/ 364 | 365 | # MSBuild Binary and Structured Log 366 | *.binlog 367 | 368 | # NVidia Nsight GPU debugger configuration file 369 | *.nvuser 370 | 371 | # MFractors (Xamarin productivity tool) working folder 372 | .mfractor/ 373 | 374 | # Local History for Visual Studio 375 | .localhistory/ 376 | 377 | # Visual Studio History (VSHistory) files 378 | .vshistory/ 379 | 380 | # BeatPulse healthcheck temp database 381 | healthchecksdb 382 | 383 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 384 | MigrationBackup/ 385 | 386 | # Ionide (cross platform F# VS Code tools) working folder 387 | .ionide/ 388 | 389 | # Fody - auto-generated XML schema 390 | FodyWeavers.xsd 391 | 392 | # VS Code files for those working on multiple tools 393 | .vscode/* 394 | !.vscode/settings.json 395 | !.vscode/tasks.json 396 | !.vscode/launch.json 397 | !.vscode/extensions.json 398 | *.code-workspace 399 | 400 | # Local History for Visual Studio Code 401 | .history/ 402 | 403 | # Windows Installer files from build outputs 404 | *.cab 405 | *.msi 406 | *.msix 407 | *.msm 408 | *.msp 409 | 410 | # JetBrains Rider 411 | *.sln.iml 412 | 413 | ## PYTHON 414 | # Byte-compiled / optimized / DLL files 415 | __pycache__/ 416 | *.py[cod] 417 | *$py.class 418 | 419 | # C extensions 420 | *.so 421 | 422 | # Distribution / packaging 423 | .Python 424 | build/ 425 | develop-eggs/ 426 | dist/ 427 | downloads/ 428 | eggs/ 429 | .eggs/ 430 | lib/ 431 | lib64/ 432 | parts/ 433 | sdist/ 434 | var/ 435 | wheels/ 436 | share/python-wheels/ 437 | *.egg-info/ 438 | .installed.cfg 439 | *.egg 440 | MANIFEST 441 | 442 | # PyInstaller 443 | # Usually these files are written by a python script from a template 444 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 445 | *.spec 446 | 447 | # Installer logs 448 | pip-log.txt 449 | pip-delete-this-directory.txt 450 | 451 | # Unit test / coverage reports 452 | htmlcov/ 453 | .tox/ 454 | .nox/ 455 | .coverage 456 | .coverage.* 457 | .cache 458 | nosetests.xml 459 | coverage.xml 460 | *.cover 461 | *.py,cover 462 | .hypothesis/ 463 | .pytest_cache/ 464 | cover/ 465 | 466 | # Translations 467 | *.mo 468 | *.pot 469 | 470 | # Django stuff: 471 | *.log 472 | local_settings.py 473 | db.sqlite3 474 | db.sqlite3-journal 475 | 476 | # Flask stuff: 477 | instance/ 478 | .webassets-cache 479 | 480 | # Scrapy stuff: 481 | .scrapy 482 | 483 | # Sphinx documentation 484 | docs/_build/ 485 | 486 | # PyBuilder 487 | .pybuilder/ 488 | target/ 489 | 490 | # Jupyter Notebook 491 | .ipynb_checkpoints 492 | 493 | # IPython 494 | profile_default/ 495 | ipython_config.py 496 | 497 | # pyenv 498 | # For a library or package, you might want to ignore these files since the code is 499 | # intended to run in multiple environments; otherwise, check them in: 500 | # .python-version 501 | 502 | # pipenv 503 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 504 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 505 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 506 | # install all needed dependencies. 507 | #Pipfile.lock 508 | 509 | # poetry 510 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. 511 | # This is especially recommended for binary packages to ensure reproducibility, and is more 512 | # commonly ignored for libraries. 513 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control 514 | #poetry.lock 515 | 516 | # pdm 517 | # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. 518 | #pdm.lock 519 | # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it 520 | # in version control. 521 | # https://pdm.fming.dev/#use-with-ide 522 | .pdm.toml 523 | 524 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm 525 | __pypackages__/ 526 | 527 | # Celery stuff 528 | celerybeat-schedule 529 | celerybeat.pid 530 | 531 | # SageMath parsed files 532 | *.sage.py 533 | 534 | # Environments 535 | .env 536 | .venv 537 | env/ 538 | venv/ 539 | ENV/ 540 | env.bak/ 541 | venv.bak/ 542 | 543 | # Spyder project settings 544 | .spyderproject 545 | .spyproject 546 | 547 | # Rope project settings 548 | .ropeproject 549 | 550 | # mkdocs documentation 551 | /site 552 | 553 | # mypy 554 | .mypy_cache/ 555 | .dmypy.json 556 | dmypy.json 557 | 558 | # Pyre type checker 559 | .pyre/ 560 | 561 | # pytype static type analyzer 562 | .pytype/ 563 | 564 | # Cython debug symbols 565 | cython_debug/ 566 | 567 | # PyCharm 568 | # JetBrains specific template is maintained in a separate JetBrains.gitignore that can 569 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore 570 | # and can be added to the global gitignore or merged into this file. For a more nuclear 571 | # option (not recommended) you can uncomment the following to ignore the entire idea folder. 572 | #.idea/ 573 | -------------------------------------------------------------------------------- /src/value.zig: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) Palash Bauri 3 | // 4 | // This Source Code Form is subject to the terms of the Mozilla Public 5 | // License, v. 2.0. If a copy of the MPL was not distributed with this 6 | // file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | // 8 | // SPDX-License-Identifier: MPL-2.0 9 | 10 | const BN_INFINITY = "অসীম"; 11 | const BN_NAN = "অসংজ্ঞাত"; 12 | const BN_TRUE = "সত্যি"; 13 | const BN_FALSE = "মিথ্যা"; 14 | const BN_NIL = "নিল"; 15 | const BN_UNKNOWN = "অজানা মান"; 16 | 17 | const std = @import("std"); 18 | const PObj = @import("object.zig").PObj; 19 | const Gc = @import("gc.zig").Gc; 20 | const writer = @import("writer.zig"); 21 | const utils = @import("utils.zig"); 22 | const BnName = @import("bengali/names.zig"); 23 | const math = std.math; 24 | const valueerrors = @import("value_errors.zig"); 25 | const CopyError = valueerrors.CopyError; 26 | 27 | pub const ParentLink = struct { 28 | prev: std.ArrayListUnmanaged(PValue), 29 | 30 | pub fn exists(self: *ParentLink, v: *PObj) bool { 31 | for (self.prev.items) |item| { 32 | if (item.isObj()) { 33 | if (@intFromPtr(v) == @intFromPtr(item.asObj()) and item.asObj().getType() == v.getType()) { 34 | return true; 35 | } 36 | } 37 | } 38 | 39 | return false; 40 | } 41 | 42 | pub fn free(self: *ParentLink, gc: *Gc) bool { 43 | self.prev.clearAndFree(gc.hal()); 44 | self.prev.deinit(gc.hal()); 45 | gc.hal().destroy(self); 46 | return true; 47 | } 48 | }; 49 | 50 | pub const PValueType = enum(u8) { 51 | Pt_Num, 52 | Pt_Bool, 53 | Pt_Nil, 54 | Pt_Obj, 55 | Pt_Unknown, 56 | 57 | pub fn toSimpleString(self: PValueType) []const u8 { 58 | switch (self) { 59 | .Pt_Num => return BnName.simpleNameNumber, 60 | .Pt_Bool => return BnName.simpleNameBool, 61 | .Pt_Nil => return BnName.simpleNameNil, 62 | .Pt_Obj => return BnName.simpleNameObject, 63 | .Pt_Unknown => return BnName.simpleNameUnknown, 64 | } 65 | } 66 | 67 | pub fn toString(self: PValueType) []const u8 { 68 | switch (self) { 69 | .Pt_Num => return "VAL_NUM", 70 | .Pt_Bool => return "VAL_BOOL", 71 | .Pt_Nil => return "VAL_NIL", 72 | .Pt_Obj => return "VAL_OBJ", 73 | .Pt_Unknown => return "VAL_UNKNOWN", 74 | } 75 | } 76 | }; 77 | 78 | pub const PValue = packed struct { 79 | data: u64, 80 | const QNAN: u64 = 0x7ffc000000000000; 81 | const SIGN_BIT: u64 = 0x8000000000000000; 82 | 83 | const TAG_NIL = 1; 84 | const TAG_FALSE = 2; 85 | const TAG_TRUE = 3; 86 | 87 | const NIL_VAL = PValue{ .data = QNAN | TAG_NIL }; 88 | const FALSE_VAL = PValue{ .data = QNAN | TAG_FALSE }; 89 | const TRUE_VAL = PValue{ .data = QNAN | TAG_TRUE }; 90 | 91 | const Self = @This(); 92 | 93 | pub fn getLen(self: Self) ?usize { 94 | if (self.isObj()) return self.asObj().getLen(); 95 | return null; 96 | } 97 | pub fn hash(self: Self) u32 { 98 | const data = self.data; 99 | var result: u32 = 0; 100 | 101 | if (utils.IS_WASM) { 102 | var hasher = std.hash.Fnv1a_32.init(); 103 | std.hash.autoHash(&hasher, data); 104 | result = hasher.final(); 105 | } else { 106 | var hasher = std.hash.XxHash32.init(@intCast(std.time.timestamp())); 107 | std.hash.autoHash(&hasher, data); 108 | result = hasher.final(); 109 | } 110 | 111 | return result; 112 | } 113 | 114 | pub fn createCopy( 115 | self: Self, 116 | gc: *Gc, 117 | links: ?*ParentLink, 118 | ) CopyError!PValue { 119 | if (self.isObj()) { 120 | const obj = self.asObj().createCopy(gc, links) catch |e| { 121 | return e; 122 | }; 123 | 124 | return PValue.makeObj(obj); 125 | } else { 126 | return self; 127 | } 128 | } 129 | 130 | /// is value a bool 131 | pub fn isBool(self: Self) bool { 132 | return (self.data | 1) == TRUE_VAL.data; 133 | } 134 | 135 | /// is value a nil 136 | pub fn isNil(self: Self) bool { 137 | return self.data == NIL_VAL.data; 138 | } 139 | 140 | /// is value a nil 141 | pub fn isNumber(self: Self) bool { 142 | return (self.data & QNAN) != QNAN; 143 | } 144 | 145 | /// is value a object 146 | pub fn isObj(self: Self) bool { 147 | return (self.data & (QNAN | SIGN_BIT)) == (QNAN | SIGN_BIT); 148 | } 149 | 150 | pub fn isMod(self: Self) bool { 151 | if (!self.isObj()) return false; 152 | if (!self.asObj().isMod()) return false; 153 | return true; 154 | } 155 | 156 | pub fn isError(self: Self) bool { 157 | return self.isObj() and self.asObj().isOError(); 158 | } 159 | 160 | pub fn isString(self: Self) bool { 161 | if (self.isObj()) { 162 | return self.asObj().isString(); 163 | } 164 | 165 | return false; 166 | } 167 | 168 | pub fn makeComptimeError( 169 | gc: *Gc, 170 | comptime msg: []const u8, 171 | args: anytype, 172 | ) ?PValue { 173 | const rawO = gc.newObj(.Ot_Error, PObj.OError) catch return null; 174 | rawO.parent().isMarked = true; 175 | if (!rawO.initU8Args(gc, msg, args)) return null; 176 | 177 | const val = PValue.makeObj(rawO.parent()); 178 | rawO.parent().isMarked = false; 179 | return val; 180 | } 181 | 182 | pub fn makeError(gc: *Gc, msg: []const u8) ?PValue { 183 | const rawO = gc.newObj(.Ot_Error, PObj.OError) catch return null; 184 | rawO.parent().isMarked = true; 185 | if (!rawO.initU8(gc, msg)) return null; 186 | const val = PValue.makeObj(rawO.parent()); 187 | rawO.parent().isMarked = false; 188 | return val; 189 | } 190 | 191 | /// get a number value as `f64` 192 | pub fn asNumber(self: Self) f64 { 193 | if (self.isNumber()) { 194 | return @bitCast(self.data); 195 | } else { 196 | return 0; 197 | } 198 | } 199 | 200 | /// get a bool value as `bool` 201 | pub fn asBool(self: Self) bool { 202 | if (self.isBool()) { 203 | return self.data == TRUE_VAL.data; 204 | } else { 205 | return false; 206 | } 207 | } 208 | 209 | pub fn asObj(self: Self) *PObj { 210 | const v: usize = @intCast(self.data & ~(SIGN_BIT | QNAN)); 211 | 212 | return @ptrFromInt(v); 213 | } 214 | 215 | pub fn asDataObj(self: Self) usize { 216 | return @as(usize, @intCast(self.data & ~(SIGN_BIT | QNAN))); 217 | } 218 | 219 | /// Create a new number value 220 | pub fn makeNumber(n: f64) PValue { 221 | return PValue{ .data = @bitCast(n) }; 222 | } 223 | 224 | /// Create a new bool value 225 | pub fn makeBool(b: bool) PValue { 226 | if (b) { 227 | return TRUE_VAL; 228 | } else { 229 | return FALSE_VAL; 230 | } 231 | } 232 | 233 | /// Create a new nil value 234 | pub fn makeNil() PValue { 235 | return NIL_VAL; 236 | } 237 | 238 | pub fn makeObj(o: *PObj) PValue { 239 | return PValue{ 240 | .data = SIGN_BIT | QNAN | @intFromPtr(o), 241 | }; 242 | } 243 | 244 | /// Return a new value with with negative value of itself; 245 | /// If `self` is not a number return itself 246 | pub fn makeNeg(self: Self) PValue { 247 | if (self.isNumber()) { 248 | return PValue.makeNumber(-self.asNumber()); 249 | } else { 250 | return self; 251 | } 252 | } 253 | 254 | pub fn getType(self: Self) PValueType { 255 | if (self.isNumber()) { 256 | return .Pt_Num; 257 | } else if (self.isBool()) { 258 | return .Pt_Bool; 259 | } else if (self.isNil()) { 260 | return .Pt_Nil; 261 | } else if (self.isObj()) { 262 | return .Pt_Obj; 263 | } 264 | 265 | return .Pt_Unknown; 266 | } 267 | 268 | pub fn getTypeAsString(self: Self) []const u8 { 269 | switch (self.getType()) { 270 | .Pt_Num, 271 | .Pt_Bool, 272 | .Pt_Nil, 273 | .Pt_Unknown, 274 | => return self.getType().toString(), 275 | .Pt_Obj => { 276 | return self.asObj().getType().toString(); 277 | }, 278 | } 279 | } 280 | 281 | pub fn getTypeAsSimpleStr(self: Self) []const u8 { 282 | switch (self.getType()) { 283 | .Pt_Num, 284 | .Pt_Bool, 285 | .Pt_Nil, 286 | .Pt_Unknown, 287 | => return self.getType().toSimpleString(), 288 | .Pt_Obj => { 289 | return self.asObj().getType().toSimpleString(); 290 | }, 291 | } 292 | } 293 | 294 | pub fn isEqual(self: Self, other: PValue) bool { 295 | if (self.getType() != other.getType()) { 296 | return false; 297 | } 298 | 299 | if (self.isBool()) { 300 | return self.asBool() == other.asBool(); 301 | } else if (self.isNumber()) { 302 | return self.asNumber() == other.asNumber(); 303 | } else if (self.isNil()) { 304 | return true; 305 | } else if (self.isObj()) { 306 | return self.asObj().isEqual(other.asObj()); 307 | } 308 | 309 | return false; 310 | } 311 | 312 | /// Chec if value is falsy 313 | pub fn isFalsy(self: Self) bool { 314 | if (self.isBool()) { 315 | return !self.asBool(); 316 | } else if (self.isNil()) { 317 | return true; 318 | } else { 319 | return false; 320 | } 321 | } 322 | 323 | pub fn printValForShow(self: Self, gc: *Gc, links: ?*ParentLink) bool { 324 | if (self.isObj() and self.asObj().isString()) { 325 | return self.asObj().asString().printWithoutQuotes(gc); 326 | } 327 | 328 | return self.printVal(gc, links); 329 | } 330 | 331 | /// Print value of PValue to console 332 | pub fn printVal(self: Self, gc: *Gc, links: ?*ParentLink) bool { 333 | if (self.isNil()) { 334 | gc.pstdout.print(BN_NIL, .{}) catch return false; 335 | } else if (self.isBool()) { 336 | const b: bool = self.asBool(); 337 | if (b) { 338 | gc.pstdout.print(BN_TRUE, .{}) catch return false; 339 | } else { 340 | gc.pstdout.print(BN_FALSE, .{}) catch return false; 341 | } 342 | } else if (self.isNumber()) { 343 | const n: f64 = self.asNumber(); 344 | if (math.isInf(n)) { 345 | gc.pstdout.print(BN_INFINITY, .{}) catch return false; 346 | } else if (math.isNan(n)) { 347 | gc.pstdout.print(BN_NAN, .{}) catch return false; 348 | } else { 349 | gc.pstdout.print("{d}", .{n}) catch return false; 350 | } 351 | } else if (self.isObj()) { 352 | return self.asObj().printObj(gc, links); 353 | } else { 354 | gc.pstdout.print(BN_UNKNOWN, .{}) catch return false; 355 | } 356 | 357 | return true; 358 | } 359 | 360 | /// Convert value to string 361 | /// you must free the result 362 | pub fn toString(self: Self, al: std.mem.Allocator) ![]u8 { 363 | if (self.isNil()) { 364 | const r = try std.fmt.allocPrint(al, BN_NIL, .{}); 365 | return r; 366 | } else if (self.isBool()) { 367 | if (self.asBool()) { 368 | const r = try std.fmt.allocPrint(al, BN_TRUE, .{}); 369 | return r; 370 | } else { 371 | const r = try std.fmt.allocPrint(al, BN_FALSE, .{}); 372 | return r; 373 | } 374 | } else if (self.isNumber()) { 375 | var mstr: []u8 = undefined; 376 | 377 | const num = self.asNumber(); 378 | 379 | if (math.isInf(num)) { 380 | mstr = try std.fmt.allocPrint(al, BN_INFINITY, .{}); 381 | } else if (math.isNan(num)) { 382 | mstr = try std.fmt.allocPrint(al, BN_NAN, .{}); 383 | } else { 384 | mstr = try std.fmt.allocPrint(al, "{d}", .{self.asNumber()}); 385 | } 386 | return mstr; 387 | } else if (self.isObj()) { 388 | return try self.asObj().toString(al); 389 | } 390 | var r = try al.alloc(u8, 1); 391 | r[0] = '_'; 392 | return r; 393 | } 394 | }; 395 | 396 | test "bool values" { 397 | try std.testing.expect(PValue.makeBool(true).asBool() == true); 398 | try std.testing.expectEqual(false, PValue.makeBool(!true).asBool()); 399 | try std.testing.expectEqual(false, PValue.makeBool(true).isNumber()); 400 | try std.testing.expectEqual(false, PValue.makeBool(true).isNil()); 401 | try std.testing.expectEqual(false, PValue.makeBool(true).isFalsy()); 402 | try std.testing.expectEqual(true, PValue.makeBool(false).isFalsy()); 403 | } 404 | 405 | test "number values" { 406 | const hundred: f64 = 100.0; 407 | const nnnn: f64 = 99.99; 408 | try std.testing.expect( 409 | PValue.makeNumber(@floatCast(100)).asNumber() == hundred, 410 | ); 411 | try std.testing.expect( 412 | PValue.makeNumber(@floatCast(99.99)).asNumber() == nnnn, 413 | ); 414 | try std.testing.expect(PValue.makeNumber(@floatCast(1)).isBool() == false); 415 | try std.testing.expect(PValue.makeNumber(@floatCast(1)).isNil() == false); 416 | } 417 | 418 | test "nil value" { 419 | try std.testing.expectEqual(PValue.makeNil(), PValue.makeNil()); 420 | try std.testing.expectEqual(true, PValue.makeNil().isNil()); 421 | try std.testing.expectEqual(false, PValue.makeNil().isBool()); 422 | try std.testing.expectEqual(false, PValue.makeNil().isNumber()); 423 | } 424 | --------------------------------------------------------------------------------