├── examples
├── hello.sop
├── 25_constant_type_error.sop
├── 22_constant_reassignment_test.sop
├── 01_dynamic_typing.sop
├── 24_constant_type_error_test.sop
├── type_test.sop
├── 19_list_filter.sop
├── 15_user_input.sop
├── return_test.sop
├── 02_static_typing.sop
├── 08_for_loops.sop
├── 05_comparison_operators.sop
├── test_operators.sop
├── 03_type_checking.sop
├── 18_list_clear.sop
├── 20_constants.sop
├── 19_list_filter_complex.sop
├── 33_string_methods.sop
├── 27_list_transform.sop
├── 23_constant_type_check.sop
├── 17_list_reverse.sop
├── 09_while_loops.sop
├── 04_arithmetic_operators.sop
├── 06_logical_operators.sop
├── 11_list_operations.sop
├── 16_list_copy.sop
├── 34_string_contains.sop
├── 18_list_sort.sop
├── 35_math_floor.sop
├── 07_conditional_statements.sop
├── 21_practical_constants.sop
├── 32_object_entries.sop
├── 28_list_raadso_and_negative_indexing.sop
├── 36_math_ceil.sop
├── 31_object_values.sop
├── 41_string_slice.sop
├── 29_object_copy.sop
├── 30_object_clear.sop
├── 37_string_endswith.sop
├── 38_string_startswith.sop
├── 26_list_slice.sop
├── 14_comparison_assignment.sop
├── 40_string_join.sop
├── 12_object_operations.sop
├── 42_universal_length.sop
├── 39_string_replace.sop
├── 09_switch_case.sop
├── 13_type_conversion.sop
├── 10_functions.sop
├── 15_switch_case.sop
└── 43_random_function.sop
├── bun.lockb
├── .prettierignore
├── public
├── favicon.ico
├── images
│ ├── logo
│ │ ├── logo-128.jpg
│ │ ├── logo-128.png
│ │ ├── logo-512.jpg
│ │ ├── logo-512.png
│ │ ├── logo-dark.png
│ │ ├── logo-light.png
│ │ ├── logo.svg
│ │ ├── logo-128.svg
│ │ └── logo-512.svg
│ ├── testimonials
│ │ ├── tood.png
│ │ ├── omartood.svg
│ │ ├── ismailainte.svg
│ │ └── mrsharafdin.svg
│ ├── blog
│ │ ├── soplang-2.0.svg
│ │ ├── hackathon.svg
│ │ ├── community-milestone.svg
│ │ ├── enterprise-adoption.svg
│ │ ├── learning-resources.svg
│ │ ├── release-1.5.0.svg
│ │ ├── university-adoption.svg
│ │ └── community-contributions.svg
│ └── sponsors
│ │ └── Docker.svg
├── favicon
│ ├── favicon-16x16.png
│ ├── favicon-32x32.png
│ ├── apple-touch-icon.png
│ ├── android-chrome-192x192.png
│ ├── android-chrome-512x512.png
│ └── site.webmanifest
├── robots.txt
├── site.webmanifest
└── sitemap.xml
├── postcss.config.js
├── .prettierrc.json
├── src
├── app
│ ├── downloads
│ │ ├── archive
│ │ │ └── layout.tsx
│ │ └── latest
│ │ │ └── layout.tsx
│ ├── about
│ │ ├── news
│ │ │ └── page.tsx
│ │ ├── license
│ │ │ └── page.tsx
│ │ ├── foundation
│ │ │ └── page.tsx
│ │ ├── help
│ │ │ └── layout.tsx
│ │ ├── applications
│ │ │ └── layout.tsx
│ │ └── quotes
│ │ │ └── page.tsx
│ ├── news
│ │ ├── page.tsx
│ │ └── not-found.tsx
│ ├── docs
│ │ ├── faq
│ │ │ └── layout.tsx
│ │ ├── input-and-output
│ │ │ └── page.tsx
│ │ └── objects
│ │ │ └── page.tsx
│ ├── contribute
│ │ ├── layout.tsx
│ │ └── security
│ │ │ └── layout.tsx
│ ├── search
│ │ └── layout.tsx
│ ├── test
│ │ └── page.tsx
│ ├── not-found.tsx
│ └── sitemap
│ │ └── page.tsx
├── lib
│ └── utils.ts
├── styles
│ ├── terminal.css
│ └── soplang-syntax.css
├── hooks
│ └── use-meta-color.ts
├── utils
│ └── formatDate.ts
└── components
│ ├── ThemeToggle.tsx
│ ├── SoplangCodeWindow.tsx
│ ├── ui
│ ├── button.tsx
│ └── mode-switcher.tsx
│ ├── CodeSnippet.tsx
│ └── DocNavigation.tsx
├── start-dev.sh
├── push-changes.sh
├── force-push.sh
├── .gitignore
├── start-dev-with-colors.sh
├── components.json
├── md
├── 02_input_output.md
├── 08_functions.md
├── 01_syntax.md
├── 10_objects.md
├── 03_variables.md
├── 07_loops.md
├── 04_type_conversion.md
├── 06_control_flow.md
├── 05_operators.md
├── 11_strings.md
├── 09_arrays.md
├── 12_builtins.md
└── info.md
├── tsconfig.json
├── temp_backup
└── src
│ ├── utils
│ └── formatDate.ts
│ ├── styles
│ └── globals.css
│ ├── app
│ └── layout.tsx
│ └── components
│ ├── ThemeToggle.tsx
│ └── ThemeProvider.tsx
├── tailwind.config.js
├── LICENSE
├── next.config.js
├── package.json
├── scripts
├── generate-placeholders.js
└── generate-news-images.js
└── README.md
/examples/hello.sop:
--------------------------------------------------------------------------------
1 | qor("Salaan, Adduunka!")
2 |
--------------------------------------------------------------------------------
/bun.lockb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/soplang/soplang.org/HEAD/bun.lockb
--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------
1 | # Ignore artifacts:
2 | build
3 | coverage
4 | node_modules/
5 | .next/
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/soplang/soplang.org/HEAD/public/favicon.ico
--------------------------------------------------------------------------------
/public/images/logo/logo-128.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/soplang/soplang.org/HEAD/public/images/logo/logo-128.jpg
--------------------------------------------------------------------------------
/public/images/logo/logo-128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/soplang/soplang.org/HEAD/public/images/logo/logo-128.png
--------------------------------------------------------------------------------
/public/images/logo/logo-512.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/soplang/soplang.org/HEAD/public/images/logo/logo-512.jpg
--------------------------------------------------------------------------------
/public/images/logo/logo-512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/soplang/soplang.org/HEAD/public/images/logo/logo-512.png
--------------------------------------------------------------------------------
/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: {
3 | tailwindcss: {},
4 | autoprefixer: {},
5 | },
6 | }
--------------------------------------------------------------------------------
/public/favicon/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/soplang/soplang.org/HEAD/public/favicon/favicon-16x16.png
--------------------------------------------------------------------------------
/public/favicon/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/soplang/soplang.org/HEAD/public/favicon/favicon-32x32.png
--------------------------------------------------------------------------------
/public/images/logo/logo-dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/soplang/soplang.org/HEAD/public/images/logo/logo-dark.png
--------------------------------------------------------------------------------
/public/images/logo/logo-light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/soplang/soplang.org/HEAD/public/images/logo/logo-light.png
--------------------------------------------------------------------------------
/public/favicon/apple-touch-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/soplang/soplang.org/HEAD/public/favicon/apple-touch-icon.png
--------------------------------------------------------------------------------
/public/images/testimonials/tood.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/soplang/soplang.org/HEAD/public/images/testimonials/tood.png
--------------------------------------------------------------------------------
/.prettierrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "singleQuote": true,
3 | "trailingComma": "all",
4 | "printWidth": 100,
5 | "semi": true
6 | }
7 |
--------------------------------------------------------------------------------
/public/favicon/android-chrome-192x192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/soplang/soplang.org/HEAD/public/favicon/android-chrome-192x192.png
--------------------------------------------------------------------------------
/public/favicon/android-chrome-512x512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/soplang/soplang.org/HEAD/public/favicon/android-chrome-512x512.png
--------------------------------------------------------------------------------
/src/app/downloads/archive/layout.tsx:
--------------------------------------------------------------------------------
1 | export default function ArchiveLayout({
2 | children,
3 | }: {
4 | children: React.ReactNode;
5 | }) {
6 | return <>{children}>;
7 | }
8 |
--------------------------------------------------------------------------------
/src/app/about/news/page.tsx:
--------------------------------------------------------------------------------
1 | import { notFound } from "next/navigation";
2 |
3 | export default function AboutNewsPage() {
4 | // Make this page inaccessible
5 | notFound();
6 | }
7 |
--------------------------------------------------------------------------------
/src/app/downloads/latest/layout.tsx:
--------------------------------------------------------------------------------
1 | export default function LatestVersionLayout({
2 | children,
3 | }: {
4 | children: React.ReactNode;
5 | }) {
6 | return <>{children}>;
7 | }
8 |
--------------------------------------------------------------------------------
/src/app/about/license/page.tsx:
--------------------------------------------------------------------------------
1 | import { notFound } from "next/navigation";
2 |
3 | export default function AboutLicensePage() {
4 | // Make this page inaccessible
5 | notFound();
6 | }
7 |
--------------------------------------------------------------------------------
/src/app/news/page.tsx:
--------------------------------------------------------------------------------
1 | import { notFound } from "next/navigation";
2 |
3 | export default function NewsPage() {
4 | // This entire section is no longer accessible
5 | notFound();
6 | }
7 |
--------------------------------------------------------------------------------
/src/app/about/foundation/page.tsx:
--------------------------------------------------------------------------------
1 | import { notFound } from "next/navigation";
2 |
3 | export default function AboutFoundationPage() {
4 | // Make this page inaccessible
5 | notFound();
6 | }
7 |
--------------------------------------------------------------------------------
/src/lib/utils.ts:
--------------------------------------------------------------------------------
1 | import { clsx, type ClassValue } from "clsx"
2 | import { twMerge } from "tailwind-merge"
3 |
4 | export function cn(...inputs: ClassValue[]) {
5 | return twMerge(clsx(inputs))
6 | }
7 |
--------------------------------------------------------------------------------
/public/favicon/site.webmanifest:
--------------------------------------------------------------------------------
1 | {"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"}
--------------------------------------------------------------------------------
/start-dev.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # Set environment variables to help with hydration issues
4 | export NODE_ENV=development
5 | export NEXT_PUBLIC_SUPPRESS_HYDRATION_WARNING=true
6 |
7 | # Start the Next.js development server
8 | echo "Starting Soplang.org development server..."
9 | npm run dev
--------------------------------------------------------------------------------
/push-changes.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # Add all changes
4 | git add .
5 |
6 | # Commit the changes
7 | git commit -m "Add new pages: Download Latest, Get Started, Reference, Forums, and Contribute"
8 |
9 | # Push to GitHub
10 | git push origin main
11 |
12 | echo "Changes pushed to GitHub successfully!"
--------------------------------------------------------------------------------
/force-push.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # Add all changes
4 | git add .
5 |
6 | # Commit the changes
7 | git commit -m "Add new pages: Download Latest, Get Started, Reference, Forums, and Contribute"
8 |
9 | # Force push to GitHub (use with caution)
10 | git push -f origin main
11 |
12 | echo "Changes force pushed to GitHub successfully!"
--------------------------------------------------------------------------------
/public/images/testimonials/omartood.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | OT
5 |
6 |
--------------------------------------------------------------------------------
/public/images/testimonials/ismailainte.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | IA
5 |
6 |
--------------------------------------------------------------------------------
/public/images/testimonials/mrsharafdin.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | MS
5 |
6 |
--------------------------------------------------------------------------------
/src/app/docs/faq/layout.tsx:
--------------------------------------------------------------------------------
1 | import { Metadata } from 'next';
2 |
3 | export const metadata: Metadata = {
4 | title: 'Frequently Asked Questions - Soplang',
5 | description: 'Find answers to common questions about Soplang programming language, installation, usage, and more.',
6 | };
7 |
8 | export default function FAQLayout({
9 | children,
10 | }: {
11 | children: React.ReactNode;
12 | }) {
13 | return children;
14 | }
--------------------------------------------------------------------------------
/src/app/about/help/layout.tsx:
--------------------------------------------------------------------------------
1 | import { Metadata } from 'next';
2 |
3 | export const metadata: Metadata = {
4 | title: 'Help Center - Soplang',
5 | description: 'Get help with Soplang programming language. Find documentation, community support, and answers to common questions.',
6 | };
7 |
8 | export default function HelpLayout({
9 | children,
10 | }: {
11 | children: React.ReactNode;
12 | }) {
13 | return children;
14 | }
--------------------------------------------------------------------------------
/public/robots.txt:
--------------------------------------------------------------------------------
1 | # Allow all crawlers
2 | User-agent: *
3 | Allow: /
4 |
5 | # Sitemap location
6 | Sitemap: https://soplang.org/sitemap.xml
7 |
8 | # Prevent crawling of development/test environments
9 | User-agent: *
10 | Disallow: /api/
11 | Disallow: /admin/
12 | Disallow: /dev/
13 | Disallow: /test/
14 |
15 | # Rate limiting for heavy crawlers
16 | User-agent: AhrefsBot
17 | Crawl-delay: 10
18 |
19 | User-agent: SemrushBot
20 | Crawl-delay: 10
--------------------------------------------------------------------------------
/src/app/contribute/layout.tsx:
--------------------------------------------------------------------------------
1 | import { Metadata } from 'next';
2 |
3 | export const metadata: Metadata = {
4 | title: 'Contribute to Soplang',
5 | description:
6 | 'Learn how to contribute to the Soplang programming language and become part of our growing community of developers.',
7 | };
8 |
9 | export default function ContributeLayout({
10 | children,
11 | }: {
12 | children: React.ReactNode;
13 | }) {
14 | return children;
15 | }
16 |
--------------------------------------------------------------------------------
/src/app/about/applications/layout.tsx:
--------------------------------------------------------------------------------
1 | import { Metadata } from 'next';
2 |
3 | export const metadata: Metadata = {
4 | title: 'Applications - Soplang',
5 | description: 'Discover how Soplang is used across different industries and applications, from web development to data science and beyond.',
6 | };
7 |
8 | export default function ApplicationsLayout({
9 | children,
10 | }: {
11 | children: React.ReactNode;
12 | }) {
13 | return children;
14 | }
--------------------------------------------------------------------------------
/src/app/contribute/security/layout.tsx:
--------------------------------------------------------------------------------
1 | import { Metadata } from 'next';
2 |
3 | export const metadata: Metadata = {
4 | title: 'Report a Security Issue - Soplang',
5 | description: 'Learn how to responsibly report security vulnerabilities in Soplang and understand our security response process.',
6 | };
7 |
8 | export default function SecurityLayout({
9 | children,
10 | }: {
11 | children: React.ReactNode;
12 | }) {
13 | return children;
14 | }
--------------------------------------------------------------------------------
/src/app/search/layout.tsx:
--------------------------------------------------------------------------------
1 | import { Metadata } from "next";
2 |
3 | export const metadata: Metadata = {
4 | title: "Search Soplang - Find Documentation, Blogs, and News",
5 | description:
6 | "Search through Soplang's documentation, blog posts, news, and more to find the information you need.",
7 | };
8 |
9 | export default function SearchLayout({
10 | children,
11 | }: {
12 | children: React.ReactNode;
13 | }) {
14 | return <>{children}>;
15 | }
16 |
--------------------------------------------------------------------------------
/public/images/blog/soplang-2.0.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Soplang 2.0
5 |
6 |
7 | Soplang News
8 |
9 |
--------------------------------------------------------------------------------
/public/images/blog/hackathon.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Soplang Hackathon
5 |
6 |
7 | Soplang News
8 |
9 |
--------------------------------------------------------------------------------
/public/images/blog/community-milestone.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Community Milestone
5 |
6 |
7 | Soplang News
8 |
9 |
--------------------------------------------------------------------------------
/public/images/blog/enterprise-adoption.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Enterprise Adoption
5 |
6 |
7 | Soplang News
8 |
9 |
--------------------------------------------------------------------------------
/public/images/blog/learning-resources.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Learning Resources
5 |
6 |
7 | Soplang News
8 |
9 |
--------------------------------------------------------------------------------
/public/images/blog/release-1.5.0.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Soplang 1.5.0 Release
5 |
6 |
7 | Soplang News
8 |
9 |
--------------------------------------------------------------------------------
/public/images/blog/university-adoption.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | University Adoption
5 |
6 |
7 | Soplang News
8 |
9 |
--------------------------------------------------------------------------------
/public/images/blog/community-contributions.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Community Contributions
5 |
6 |
7 | Soplang News
8 |
9 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # dependencies
2 | /node_modules
3 | /.pnp
4 | .pnp.js
5 |
6 | # testing
7 | /coverage
8 |
9 | # next.js
10 | /.next/
11 | /out/
12 |
13 | # production
14 | /build
15 |
16 | # misc
17 | .DS_Store
18 | *.pem
19 |
20 | # debug
21 | npm-debug.log*
22 | yarn-debug.log*
23 | yarn-error.log*
24 |
25 | # local env files
26 | .env*.local
27 |
28 | # vercel
29 | .vercel
30 |
31 | # typescript
32 | *.tsbuildinfo
33 | next-env.d.ts
34 | .cursorrules
35 | .qodo
36 |
37 | # format files
38 | .prettierrc
39 |
--------------------------------------------------------------------------------
/examples/25_constant_type_error.sop:
--------------------------------------------------------------------------------
1 | // Test: Constant Type Error Messages
2 | // This test checks type error messages for constants
3 |
4 | qor("Testing constant type error messages:")
5 |
6 | // String constant with number value (should trigger type error)
7 | qor("\nAttempting to assign a number to a string constant:")
8 | madoor qoraal STRING_CONST = 123 // This should trigger type_mismatch error with line/position info
9 |
10 | qor("If you see this message, the type error was not enforced properly")
11 |
--------------------------------------------------------------------------------
/start-dev-with-colors.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # Set environment variables to help with hydration issues
4 | export NODE_ENV=development
5 | export NEXT_PUBLIC_SUPPRESS_HYDRATION_WARNING=true
6 |
7 | # Print color information
8 | echo "Starting Soplang.org development server with custom colors:"
9 | echo "Primary Color: #1E3A8A (Default blue)"
10 | echo "Secondary Color: #F59E0B (Default orange)"
11 | echo ""
12 |
13 | # Start the Next.js development server
14 | echo "Starting development server..."
15 | npm run dev
--------------------------------------------------------------------------------
/components.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://ui.shadcn.com/schema.json",
3 | "style": "new-york",
4 | "rsc": true,
5 | "tsx": true,
6 | "tailwind": {
7 | "config": "tailwind.config.js",
8 | "css": "src/styles/globals.css",
9 | "baseColor": "neutral",
10 | "cssVariables": true,
11 | "prefix": ""
12 | },
13 | "aliases": {
14 | "components": "@/components",
15 | "utils": "@/lib/utils",
16 | "ui": "@/components/ui",
17 | "lib": "@/lib",
18 | "hooks": "@/hooks"
19 | },
20 | "iconLibrary": "lucide"
21 | }
--------------------------------------------------------------------------------
/src/styles/terminal.css:
--------------------------------------------------------------------------------
1 | /* Terminal typing animation */
2 | .typing-animation {
3 | border-right: 2px solid #4dabf7;
4 | animation:
5 | typing 3.5s steps(30, end),
6 | blink-caret 0.75s step-end infinite;
7 | white-space: nowrap;
8 | overflow: hidden;
9 | display: inline-block;
10 | }
11 |
12 | @keyframes typing {
13 | from {
14 | width: 0;
15 | }
16 | to {
17 | width: 100%;
18 | }
19 | }
20 |
21 | @keyframes blink-caret {
22 | from,
23 | to {
24 | border-color: transparent;
25 | }
26 | 50% {
27 | border-color: #4dabf7;
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/examples/22_constant_reassignment_test.sop:
--------------------------------------------------------------------------------
1 | // Test: Constant Reassignment Error
2 | // This test verifies that constants cannot be reassigned
3 |
4 | qor("Testing constant reassignment protection:")
5 |
6 | // Define some constants
7 | madoor PI = 3.14159
8 | madoor abn MAX_VALUE = 100
9 |
10 | qor(" Initial values:")
11 | qor(" PI = " + PI)
12 | qor(" MAX_VALUE = " + MAX_VALUE)
13 |
14 | // Trying to reassign a constant
15 | qor("Attempting to reassign PI (should cause error):")
16 | PI = 3.14 // This should fail with a runtime error
17 |
18 | // We should never reach this point
19 | qor(" This line should never be displayed")
20 |
--------------------------------------------------------------------------------
/src/hooks/use-meta-color.ts:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import { useTheme } from 'next-themes';
3 |
4 | export const META_THEME_COLORS = {
5 | light: '#ffffff',
6 | dark: '#0a0a0a',
7 | };
8 |
9 | export function useMetaColor() {
10 | const { resolvedTheme } = useTheme();
11 |
12 | const metaColor = React.useMemo(() => {
13 | return resolvedTheme !== 'dark' ? META_THEME_COLORS.light : META_THEME_COLORS.dark;
14 | }, [resolvedTheme]);
15 |
16 | const setMetaColor = React.useCallback((color: string) => {
17 | document.querySelector('meta[name="theme-color"]')?.setAttribute('content', color);
18 | }, []);
19 |
20 | return {
21 | metaColor,
22 | setMetaColor,
23 | };
24 | }
25 |
--------------------------------------------------------------------------------
/examples/01_dynamic_typing.sop:
--------------------------------------------------------------------------------
1 | // Test: Dynamic Typing (door variables)
2 | // This test checks if dynamic typing works properly
3 |
4 | qor("Testing dynamic typing (door):")
5 |
6 | // Initialize with number
7 | door dynamic_var = 10
8 | qor(" Initial value (number): " + dynamic_var)
9 |
10 | // Change to string
11 | dynamic_var = "waa qoraal hadda"
12 | qor(" Changed value (string): " + dynamic_var)
13 |
14 | // Change to boolean
15 | dynamic_var = been
16 | qor(" Changed value (boolean): " + dynamic_var)
17 |
18 | // Change to list
19 | dynamic_var = [1, 2, 3]
20 | qor(" Changed value (list): " + dynamic_var)
21 |
22 | // Change to object
23 | dynamic_var = { magac: "Omar", da: 30 }
24 | qor(" Changed value (object): " + dynamic_var)
25 |
--------------------------------------------------------------------------------
/md/02_input_output.md:
--------------------------------------------------------------------------------
1 | # Input and Output in Soplang
2 |
3 | Soplang uses simple built-in functions to display output and read user input.
4 |
5 | ---
6 |
7 | ### 🖨️ `qor()` – Print to Console
8 |
9 | Use `qor()` to display values or strings on the screen.
10 |
11 | ```sop
12 | qor("Hello, Adduun!")
13 | door magaca = "Aamina"
14 | qor("Magaca: " + magaca)
15 | ```
16 |
17 | ---
18 |
19 | ### ⌨️ `gelin()` – Read from User Input
20 |
21 | Use `gelin()` to prompt the user for input. The value is always returned as a string.
22 |
23 | ```sop
24 | door magaca = gelin("Magacaaga qor: ")
25 | qor("Waad ku mahadsan tahay, " + magaca)
26 | ```
27 |
28 | You can convert input values if needed:
29 |
30 | ```sop
31 | door da = abn(gelin("Da'daada qor: "))
32 | ```
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es5",
4 | "lib": ["dom", "dom.iterable", "esnext"],
5 | "allowJs": true,
6 | "skipLibCheck": true,
7 | "strict": true,
8 | "forceConsistentCasingInFileNames": true,
9 | "noEmit": true,
10 | "esModuleInterop": true,
11 | "module": "esnext",
12 | "moduleResolution": "node",
13 | "resolveJsonModule": true,
14 | "isolatedModules": true,
15 | "jsx": "preserve",
16 | "incremental": true,
17 | "plugins": [
18 | {
19 | "name": "next"
20 | }
21 | ],
22 | "paths": {
23 | "@/*": ["./src/*"]
24 | }
25 | },
26 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
27 | "exclude": ["node_modules"]
28 | }
--------------------------------------------------------------------------------
/public/site.webmanifest:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Soplang - Somali Programming Language",
3 | "short_name": "Soplang",
4 | "description": "A Somali-first programming language that makes coding intuitive, inclusive, and accessible for Somali peoples.",
5 | "icons": [
6 | {
7 | "src": "/favicon/android-chrome-192x192.png",
8 | "sizes": "192x192",
9 | "type": "image/png"
10 | },
11 | {
12 | "src": "/favicon/android-chrome-512x512.png",
13 | "sizes": "512x512",
14 | "type": "image/png"
15 | }
16 | ],
17 | "theme_color": "#1e40af",
18 | "background_color": "#ffffff",
19 | "start_url": "/",
20 | "display": "standalone",
21 | "lang": "en-US",
22 | "orientation": "portrait-primary"
23 | }
--------------------------------------------------------------------------------
/src/utils/formatDate.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Format a date in a consistent way between server and client
3 | * to avoid hydration mismatches
4 | */
5 | export function formatDate(date: Date): string {
6 | // Use UTC methods to ensure consistent output regardless of timezone
7 | const year = date.getUTCFullYear();
8 | const month = date.getUTCMonth();
9 | const day = date.getUTCDate();
10 |
11 | // Array of month names
12 | const monthNames = [
13 | 'January', 'February', 'March', 'April', 'May', 'June',
14 | 'July', 'August', 'September', 'October', 'November', 'December'
15 | ];
16 |
17 | // Return formatted date string
18 | return `${monthNames[month]} ${day}, ${year}`;
19 | }
20 |
21 | /**
22 | * Get the current year in a consistent way between server and client
23 | */
24 | export function getCurrentYear(): number {
25 | return new Date().getUTCFullYear();
26 | }
--------------------------------------------------------------------------------
/src/app/test/page.tsx:
--------------------------------------------------------------------------------
1 | 'use client';
2 |
3 | import React from 'react';
4 | import CodeWindow from '../../components/CodeWindow';
5 |
6 | // Sample code snippet with Hello World example
7 | const codeSnippet = `// Hello World
8 | qor("Salaan, Adduunka!")
9 |
10 | // Variables
11 | door magac = 'Sharafdin'
12 | qoraal cinwaan = "Soplang Developer"
13 | tiro da = 10
14 |
15 | qor("Magaca: " + magac)
16 | qor("Cinwaanka: " + cinwaan)
17 | qor("Da'da: " + qoraal(da))
18 |
19 | // Function
20 | hawl salaan(qofka) {
21 | celi "Salaan, " + qofka + "!"
22 | }
23 | qor(salaan(magac))
24 | `;
25 |
26 | export default function TestPage() {
27 | return (
28 |
33 | );
34 | }
35 |
--------------------------------------------------------------------------------
/temp_backup/src/utils/formatDate.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Format a date in a consistent way between server and client
3 | * to avoid hydration mismatches
4 | */
5 | export function formatDate(date: Date): string {
6 | // Use UTC methods to ensure consistent output regardless of timezone
7 | const year = date.getUTCFullYear();
8 | const month = date.getUTCMonth();
9 | const day = date.getUTCDate();
10 |
11 | // Array of month names
12 | const monthNames = [
13 | 'January', 'February', 'March', 'April', 'May', 'June',
14 | 'July', 'August', 'September', 'October', 'November', 'December'
15 | ];
16 |
17 | // Return formatted date string
18 | return `${monthNames[month]} ${day}, ${year}`;
19 | }
20 |
21 | /**
22 | * Get the current year in a consistent way between server and client
23 | */
24 | export function getCurrentYear(): number {
25 | return new Date().getUTCFullYear();
26 | }
--------------------------------------------------------------------------------
/examples/24_constant_type_error_test.sop:
--------------------------------------------------------------------------------
1 | // Test: Constant Error Messages
2 | // This test checks the error messages for constants
3 |
4 | qor("Testing constant error messages:")
5 |
6 | // Test 1: Constant reassignment error
7 | qor("\n1. Testing constant reassignment error:")
8 | madoor bool TEST_CONSTANT = run
9 | qor(" Original constant value: " + TEST_CONSTANT)
10 |
11 | // Try to reassign the constant (should generate a clear Somali error message)
12 | qor(" Attempting to reassign a constant (should show error in Somali):")
13 | TEST_CONSTANT = been // This should trigger constant_reassignment error with position info
14 |
15 | // The code below should not execute due to the error above
16 | qor("\n2. Testing constant type error:")
17 | madoor qoraal STRING_CONST = 123 // This should trigger type_mismatch error
18 |
19 | qor("If you see this message, the constant was incorrectly reassigned")
20 |
--------------------------------------------------------------------------------
/examples/type_test.sop:
--------------------------------------------------------------------------------
1 | // Test: Type detection for numbers
2 | // Verify that nooc() correctly identifies types
3 |
4 | qor("Testing type detection for numbers:")
5 |
6 | // Integer type
7 | door i = 1
8 | qor("Value: " + i + " | Type: " + nooc(i)) // Should be "abn"
9 |
10 | // Float with zero decimal (should be jajab now)
11 | door f1 = 1.0
12 | qor("Value: " + f1 + " | Type: " + nooc(f1)) // Should be "jajab"
13 |
14 | // Float with non-zero decimal
15 | door f2 = 1.5
16 | qor("Value: " + f2 + " | Type: " + nooc(f2)) // Should be "jajab"
17 |
18 | // Display values
19 | qor("Display format test:")
20 | qor("Integer: " + i) // Should display as "1"
21 | qor("Float 1.0: " + f1) // Should display as "1.0"
22 | qor("Float 1.5: " + f2) // Should display as "1.5"
23 |
24 | // Test in list
25 | teed numbers = [1, 1.0, 1.5]
26 | qor("List of numbers: " + numbers) // Should display with proper formatting
27 |
28 | qor("Type detection tests completed!")
29 |
--------------------------------------------------------------------------------
/examples/19_list_filter.sop:
--------------------------------------------------------------------------------
1 | // Test: List Filter
2 | // This test checks if the shaandhee() method correctly filters lists based on conditions
3 |
4 | qor("Testing list filter (shaandhee) method:")
5 |
6 | // Create a simple function that tests if a number is greater than 5
7 | hawl is_greater_than_five(n) {
8 | celi n > 5
9 | }
10 |
11 | // Create a list of numbers
12 | teed numbers = [1, 3, 5, 7, 9]
13 | qor("Original list: " + numbers)
14 |
15 | // Filter the list to get only numbers greater than 5
16 | door filtered = numbers.shaandhee(is_greater_than_five)
17 | qor("Numbers greater than 5: " + filtered)
18 |
19 | // Try with parentheses to ensure both ways work
20 | hawl is_even(n) {
21 | celi (n % 2 == 0)
22 | }
23 |
24 | // Create another list
25 | teed more_numbers = [1, 2, 3, 4, 5, 6]
26 | qor("Second list: " + more_numbers)
27 |
28 | // Filter for even numbers
29 | door evens = more_numbers.shaandhee(is_even)
30 | qor("Even numbers: " + evens)
31 |
32 | qor("Test completed!")
33 |
--------------------------------------------------------------------------------
/examples/15_user_input.sop:
--------------------------------------------------------------------------------
1 | // Gelin (Input) Function Example
2 | // This example shows how to use gelin to get user input
3 |
4 | // First, let's print a brief explanation
5 | qor("Gelin Example - User Input in Soplang")
6 | qor("---------------------------------")
7 |
8 | // For automated testing, we'll use a hardcoded value
9 | qor("Note: For automated testing, we'll simulate user input with a hardcoded value")
10 | // door magac = gelin("Enter your name: ")
11 | door magac = "Soplang User" // Hardcoded value for testing
12 | qor("(Normally this would be: door magac = gelin('Enter your name: '))")
13 |
14 | // Display a greeting with the entered name
15 | qor("Hello, " + magac + "!")
16 | qor("Welcome to Soplang programming!")
17 |
18 | // Show the type of the input (always a string)
19 | qor("The type of your input is: " + nooc(magac))
20 |
21 | // Example of simple input processing
22 | qor("Your name has " + dherer(magac) + " characters.")
23 |
24 | // Thank the user
25 | qor("Thank you for trying gelin in Soplang!")
26 |
--------------------------------------------------------------------------------
/tailwind.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('tailwindcss').Config} */
2 | module.exports = {
3 | content: [
4 | './src/app/**/*.{js,ts,jsx,tsx}',
5 | './src/pages/**/*.{js,ts,jsx,tsx}',
6 | './src/components/**/*.{js,ts,jsx,tsx}',
7 | ],
8 | darkMode: 'class',
9 | theme: {
10 | screens: {
11 | xs: '480px',
12 | sm: '640px',
13 | md: '768px',
14 | lg: '1024px',
15 | xl: '1280px',
16 | '2xl': '1536px',
17 | },
18 | extend: {
19 | colors: {
20 | primary: 'var(--primary-color)',
21 | secondary: 'var(--secondary-color)',
22 | accent: {
23 | DEFAULT: 'hsl(var(--accent))',
24 | foreground: 'hsl(var(--accent-foreground))',
25 | },
26 | },
27 | fontFamily: {
28 | sans: ['var(--font-roboto)', 'Roboto', 'sans-serif'],
29 | },
30 | spacing: {
31 | 72: '18rem',
32 | 84: '21rem',
33 | 96: '24rem',
34 | },
35 | },
36 | },
37 | plugins: [require('tailwindcss-animate')],
38 | };
39 |
--------------------------------------------------------------------------------
/examples/return_test.sop:
--------------------------------------------------------------------------------
1 | // Test return statements with comparison operators
2 |
3 | // Test return statement with comparison operator (no parentheses)
4 | hawl test_no_parens(x) {
5 | celi x > 5
6 | }
7 |
8 | // Test return statement with comparison operator (with parentheses)
9 | hawl test_with_parens(x) {
10 | celi (x > 5)
11 | }
12 |
13 | // Test calls
14 | qor("Testing return statements with comparison operators:")
15 | qor("test_no_parens(10): " + test_no_parens(10)) // Should return run (true)
16 | qor("test_no_parens(3): " + test_no_parens(3)) // Should return been (false)
17 | qor("test_with_parens(10): " + test_with_parens(10)) // Should return run (true)
18 | qor("test_with_parens(3): " + test_with_parens(3)) // Should return been (false)
19 |
20 | // Test with more complex expressions
21 | hawl test_complex(x) {
22 | celi x > 5 && x < 15
23 | }
24 |
25 | qor("test_complex(10): " + test_complex(10)) // Should return run (true)
26 | qor("test_complex(20): " + test_complex(20)) // Should return been (false)
27 |
28 | qor("Test completed!")
29 |
--------------------------------------------------------------------------------
/src/app/news/not-found.tsx:
--------------------------------------------------------------------------------
1 | import Link from 'next/link';
2 |
3 | export default function NewsNotFound() {
4 | return (
5 |
6 |
7 |
News Article Not Found
8 |
9 | We couldn't find the news article you're looking for. It may have been moved, deleted, or never existed.
10 |
11 |
12 |
16 | Browse All News
17 |
18 |
22 | Return to Home
23 |
24 |
25 |
26 |
27 | );
28 | }
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2025 Soplang
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/examples/02_static_typing.sop:
--------------------------------------------------------------------------------
1 | // Test: Static Typing
2 | // This test checks if static typing works properly
3 |
4 | qor("Testing static typing:")
5 |
6 | // Integer (abn)
7 | abn integer_var = 42
8 | qor(" Integer (abn): " + integer_var)
9 |
10 | // Decimal (jajab)
11 | jajab decimal_var = 3.14159
12 | qor(" Decimal (jajab): " + decimal_var)
13 |
14 | // String (qoraal)
15 | qoraal string_var = "Soplang waa luqad wacan"
16 | qor(" String (qoraal): " + string_var)
17 | // Boolean (bool)
18 | bool bool_var = been
19 | qor(" Boolean (bool): " + bool_var)
20 |
21 | // List (teed)
22 | teed list_var = [1, 2, 3, "afar", been]
23 | qor(" List (teed): " + list_var)
24 |
25 | // Object (walax)
26 | walax object_var = {
27 | magac: "Ahmed",
28 | da: 25,
29 | miisaan: 72.5
30 | }
31 | qor(" Object (walax): " + object_var)
32 |
33 | // Try to assign incompatible types (should fail)
34 | // Uncomment these lines to test type enforcement
35 | // integer_var = "this should fail"
36 | // integer_var = 3.14 // should fail (no implicit conversion)
37 | // decimal_var = "not a number"
38 | // string_var = 123
39 | // bool_var = "not a boolean"
40 |
--------------------------------------------------------------------------------
/public/images/logo/logo.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
9 |
10 |
14 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/public/images/logo/logo-128.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
9 |
10 |
14 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/next.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('next').NextConfig} */
2 | const nextConfig = {
3 | reactStrictMode: true,
4 | swcMinify: true,
5 | images: {
6 | domains: [],
7 | },
8 | // Add configuration to help with hydration issues
9 | experimental: {
10 | // This helps with hydration issues by making React more tolerant of differences
11 | optimizeCss: true,
12 | // Improve client-side rendering performance
13 | optimizeServerReact: true,
14 | },
15 | // Redirect routes for success-stories to prevent access
16 | async redirects() {
17 | return [
18 | {
19 | source: "/success-stories",
20 | destination: "/",
21 | permanent: false,
22 | },
23 | {
24 | source: "/success-stories/:path*",
25 | destination: "/",
26 | permanent: false,
27 | },
28 | // Redirect forums to GitHub Discussions
29 | {
30 | source: "/community/forums",
31 | destination: "https://github.com/orgs/soplang/discussions",
32 | permanent: false,
33 | },
34 | {
35 | source: "/community/forums/:path*",
36 | destination: "https://github.com/orgs/soplang/discussions",
37 | permanent: false,
38 | },
39 | ];
40 | },
41 | };
42 |
43 | module.exports = nextConfig;
44 |
--------------------------------------------------------------------------------
/temp_backup/src/styles/globals.css:
--------------------------------------------------------------------------------
1 | @tailwind base;
2 | @tailwind components;
3 | @tailwind utilities;
4 |
5 | :root {
6 | --primary-color: #1E3A8A; /* Default blue */
7 | --secondary-color: #F59E0B; /* Default orange */
8 | --background-color: #FFFFFF;
9 | --text-color: #1F2937;
10 | }
11 |
12 | .dark {
13 | --primary-color: #3B82F6; /* Lighter blue for dark mode */
14 | --secondary-color: #F59E0B; /* Same orange */
15 | --background-color: #111827;
16 | --text-color: #F9FAFB;
17 | }
18 |
19 | body {
20 | background-color: var(--background-color);
21 | color: var(--text-color);
22 | transition: background-color 0.3s ease, color 0.3s ease;
23 | }
24 |
25 | @layer components {
26 | .container-custom {
27 | @apply max-w-7xl mx-auto px-4 sm:px-6 lg:px-8;
28 | }
29 |
30 | .btn-primary {
31 | @apply bg-primary text-white px-4 py-2 rounded-md hover:opacity-90 transition-opacity;
32 | }
33 |
34 | .btn-secondary {
35 | @apply bg-secondary text-white px-4 py-2 rounded-md hover:opacity-90 transition-opacity;
36 | }
37 |
38 | .nav-link {
39 | @apply text-gray-700 dark:text-gray-300 hover:text-primary dark:hover:text-primary transition-colors;
40 | }
41 |
42 | .nav-link-active {
43 | @apply text-primary dark:text-primary font-medium;
44 | }
45 | }
--------------------------------------------------------------------------------
/examples/08_for_loops.sop:
--------------------------------------------------------------------------------
1 | // Test: For Loops
2 | // This test checks if for loops work properly
3 |
4 | qor("Testing for loops (kuceli):")
5 |
6 | // Simple for loop
7 | qor(" Simple for loop:")
8 | kuceli (i 1 ilaa 5) {
9 | qor(" Iteration: " + i)
10 | }
11 |
12 | // For loop with step
13 | qor(" For loop with custom step (every other number):")
14 | kuceli (j 2 ilaa 10 :: 2) {
15 | qor(" Iteration: " + j)
16 | }
17 |
18 | // For loop with break
19 | qor(" For loop with break (jooji):")
20 | kuceli (i 1 ilaa 10) {
21 | haddii (i > 5) {
22 | jooji
23 | }
24 | qor(" Iteration: " + i)
25 | }
26 |
27 | // For loop with continue
28 | qor(" For loop with continue (soco):")
29 | kuceli (i 1 ilaa 5) {
30 | haddii (i % 2 == 0) {
31 | soco
32 | }
33 | qor(" Odd number: " + i)
34 | }
35 |
36 | // Nested for loops
37 | qor(" Nested for loops:")
38 | kuceli (i 1 ilaa 3) {
39 | qor(" Outer loop: " + i)
40 | kuceli (j 1 ilaa 2) {
41 | qor(" Inner loop: " + j)
42 | }
43 | }
44 |
45 | // For loop operating on a list
46 | teed numbers = [10, 20, 30, 40, 50]
47 | qor(" For loop iterating over a list with indices:")
48 | kuceli (i 0 ilaa numbers.dherer() - 1) {
49 | qor(" Element at index " + i + ": " + numbers[i])
50 | }
51 |
--------------------------------------------------------------------------------
/public/images/logo/logo-512.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
9 |
10 |
15 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/examples/05_comparison_operators.sop:
--------------------------------------------------------------------------------
1 | // Test: Comparison Operators
2 | // This test checks if comparison operators work properly
3 |
4 | qor("Testing comparison operators:")
5 |
6 | // Integer comparisons
7 | abn a = 15
8 | abn b = 5
9 | abn c = 15
10 | qor(" a = " + a + ", b = " + b + ", c = " + c)
11 |
12 | qor("Integer comparisons:")
13 | qor(" Equal (a == c): " + (a == c))
14 | qor(" Not equal (a != b): " + (a != b))
15 | qor(" Greater than (a > b): " + (a > b))
16 | qor(" Less than (a < b): " + (a < b))
17 | qor(" Greater than or equal (a >= c): " + (a >= c))
18 | qor(" Less than or equal (a <= c): " + (a <= c))
19 |
20 | // Decimal comparisons
21 | jajab x = 15.5
22 | jajab y = 5.25
23 | jajab z = 15.5
24 | qor("\nDecimal comparisons:")
25 | qor(" x = " + x + ", y = " + y + ", z = " + z)
26 | qor(" Equal (x == z): " + (x == z))
27 | qor(" Not equal (x != y): " + (x != y))
28 | qor(" Greater than (x > y): " + (x > y))
29 | qor(" Less than (x < y): " + (x < y))
30 | qor(" Greater than or equal (x >= z): " + (x >= z))
31 | qor(" Less than or equal (x <= z): " + (x <= z))
32 |
33 | // Mixed type comparisons
34 | qor("\nMixed type comparisons:")
35 | qor(" Integer vs. Decimal (a == x): " + (a == x))
36 | qor(" Integer vs. Decimal (a < x): " + (a < x))
37 | qor(" Integer vs. Decimal (b <= y): " + (b <= y))
38 |
--------------------------------------------------------------------------------
/examples/test_operators.sop:
--------------------------------------------------------------------------------
1 | // Test file for operator parsing issues
2 |
3 | qor("Testing operator parsing:")
4 |
5 | // Test comparison operators in assignments
6 | abn score = 85
7 | qor("score = " + score)
8 |
9 | // This should now work without parentheses
10 | door is_high_score = score >= 80
11 | qor("is_high_score = " + is_high_score)
12 |
13 | // Test with parentheses too
14 | door is_passing = (score >= 60)
15 | qor("is_passing = " + is_passing)
16 |
17 | // Test with dooro statement
18 | qor("\nTesting dooro with comparison:")
19 |
20 | // This should now work directly with a comparison
21 | dooro (score >= 80) {
22 | xaalad run {
23 | qor("High score achieved!")
24 | }
25 | xaalad been {
26 | qor("Keep practicing")
27 | }
28 | }
29 |
30 | // Test complex conditions
31 | door complex_condition = (score > 60 && score < 90)
32 | qor("complex_condition = " + complex_condition)
33 |
34 | // Test list with comparisons
35 | teed test_list = [score > 80, score < 90, score == 85]
36 | qor("test_list = " + test_list)
37 |
38 | // Test object with comparisons
39 | walax test_obj = {
40 | high_score: score >= 80,
41 | passing: score >= 60,
42 | perfect: score == 100
43 | }
44 | qor("test_obj.high_score = " + test_obj.high_score)
45 | qor("test_obj.perfect = " + test_obj.perfect)
46 |
47 | qor("\nTest completed")
48 |
--------------------------------------------------------------------------------
/md/08_functions.md:
--------------------------------------------------------------------------------
1 | # Functions in Soplang
2 |
3 | Functions in Soplang are declared using the keyword `hawl` and return values using the keyword `celi`.
4 |
5 | ---
6 |
7 | ### 🛠️ Define a Function – `hawl`
8 |
9 | A function starts with `hawl`, followed by the function name and parameters (no type annotations).
10 |
11 | ```sop
12 | hawl salaan(magac) {
13 | qor("Asalaamu calaykum, " + magac)
14 | }
15 | ```
16 |
17 | ---
18 |
19 | ### 🧾 Call a Function
20 |
21 | Once defined, call the function by name:
22 |
23 | ```sop
24 | salaan("Aamina")
25 | ```
26 |
27 | ---
28 |
29 | ### 🔁 Return Values – `celi`
30 |
31 | Use `celi` to return a value from a function.
32 |
33 | ```sop
34 | hawl labanlaab(x) {
35 | celi x * 2
36 | }
37 |
38 | abn natiijo = labanlaab(5)
39 | qor("Natiijo: " + natiijo)
40 | ```
41 |
42 | ---
43 |
44 | ### 🔄 Loops Inside Functions
45 |
46 | Functions can contain loops and logic like any regular Soplang block:
47 |
48 | ```sop
49 | hawl muujin(liis) {
50 | kuceli (i 0 ilaa liis.dherer() - 1) {
51 | qor("Liiska: " + liis[i])
52 | }
53 | }
54 | ```
55 |
56 | ---
57 |
58 | ### ✅ Summary
59 |
60 | | Keyword | Meaning |
61 | |-----------|---------------------|
62 | | `hawl` | function definition |
63 | | `celi` | return value |
64 |
65 | Functions in Soplang make code reusable and clean while using native Somali terms.
66 |
--------------------------------------------------------------------------------
/examples/03_type_checking.sop:
--------------------------------------------------------------------------------
1 | // Test: Type Checking
2 | // This test checks if the nooc function works properly for detecting types
3 |
4 | qor("Testing type checking (nooc):")
5 |
6 | // Create variables of different types
7 | abn integer_var = 42
8 | jajab decimal_var = 3.14159
9 | qoraal string_var = "Soplang waa luqad wacan"
10 | bool bool_var = been
11 | teed list_var = [1, 2, 3, "afar", been]
12 | walax object_var = {
13 | magac: "Ahmed",
14 | da: 25
15 | }
16 | door dynamic_var = "dynamic"
17 |
18 | // Check types with nooc function
19 | qor(" Type of integer_var: " + nooc(integer_var))
20 | qor(" Type of decimal_var: " + nooc(decimal_var))
21 | qor(" Type of string_var: " + nooc(string_var))
22 | qor(" Type of bool_var: " + nooc(bool_var))
23 | qor(" Type of list_var: " + nooc(list_var))
24 | qor(" Type of object_var: " + nooc(object_var))
25 | qor(" Type of dynamic_var: " + nooc(dynamic_var))
26 |
27 | // Change type of dynamic variable and check again
28 | dynamic_var = 100
29 | qor(" Type of dynamic_var after change: " + nooc(dynamic_var))
30 |
31 | // Check type of literal values
32 | qor(" Type of literal integer: " + nooc(123))
33 | qor(" Type of literal decimal: " + nooc(45.67))
34 | qor(" Type of literal string: " + nooc("test"))
35 | qor(" Type of literal boolean: " + nooc(run))
36 | qor(" Type of literal list: " + nooc([1, 2, 3]))
37 | qor(" Type of literal object: " + nooc({a: 1, b: 2}))
38 |
--------------------------------------------------------------------------------
/examples/18_list_clear.sop:
--------------------------------------------------------------------------------
1 | // Test: List Clear Operations
2 | // This example demonstrates the nadiifi() method for clearing lists
3 |
4 | qor("Testing list clear (nadiifi) method:")
5 |
6 | // Basic usage as shown in the example
7 | qor("1. Basic usage:")
8 | teed xasuus = ["A", "B", "C"]
9 | qor(" Original list: " + xasuus)
10 | xasuus.nadiifi()
11 | qor(" After nadiifi(): " + xasuus)
12 |
13 | // Clearing an already empty list
14 | qor("2. Clearing an already empty list:")
15 | teed madhan = []
16 | qor(" Empty list: " + madhan)
17 | madhan.nadiifi()
18 | qor(" After nadiifi(): " + madhan)
19 |
20 | // Clearing a list with nested elements
21 | qor("3. Clearing a list with nested elements:")
22 | teed complex = [[1, 2], [3, 4], 5, "text"]
23 | qor(" Complex list: " + complex)
24 | complex.nadiifi()
25 | qor(" After nadiifi(): " + complex)
26 |
27 | // Adding items to a cleared list
28 | qor("4. Adding items to a cleared list:")
29 | teed list = [10, 20, 30]
30 | qor(" Original list: " + list)
31 | list.nadiifi()
32 | qor(" After nadiifi(): " + list)
33 | list.kudar(40)
34 | list.kudar(50)
35 | qor(" After adding new items: " + list)
36 |
37 | // Chaining operations
38 | qor("5. Chaining operations with nadiifi():")
39 | teed chain = [1, 2, 3]
40 | qor(" Original list: " + chain)
41 | chain.nadiifi().kudar(4).kudar(5)
42 | qor(" After: chain.nadiifi().kudar(4).kudar(5): " + chain)
43 |
44 | qor("The nadiifi() method successfully clears all items from a list.")
45 |
--------------------------------------------------------------------------------
/examples/20_constants.sop:
--------------------------------------------------------------------------------
1 | // Test: Constants (madoor)
2 | // This test demonstrates the use of 'madoor' for declaring constant variables
3 |
4 | qor("Testing constant variables (madoor):")
5 |
6 | // Example 1: Dynamic constant (type inferred at runtime)
7 | madoor PI = 3.14159
8 | qor(" Dynamic constant PI: " + PI)
9 |
10 | // Example 2: Typed constant (explicit type)
11 | madoor abn MAX_USERS = 100
12 | qor(" Typed constant MAX_USERS: " + MAX_USERS)
13 |
14 | madoor qoraal APP_NAME = "Soplang"
15 | qor(" Typed string constant APP_NAME: " + APP_NAME)
16 |
17 | madoor bool IS_PRODUCTION = been
18 | qor(" Typed boolean constant IS_PRODUCTION: " + IS_PRODUCTION)
19 |
20 | // Use constants in expressions
21 | abn radius = 5
22 | jajab area = PI * radius * radius
23 | qor(" Area of circle with radius " + radius + ": " + area)
24 |
25 | // Create array with max capacity from constant
26 | teed users = []
27 | kuceli (i 0 ilaa 3) {
28 | users.kudar("User " + i)
29 | }
30 | qor(" Users: " + users)
31 | qor(" Max users: " + MAX_USERS)
32 |
33 | // Try to reassign constants (should fail)
34 | qor("Trying to reassign constants (should fail):")
35 | qor(" PI = 3.14")
36 |
37 | // Uncomment to see the error:
38 | // PI = 3.14 // Runtime error: Cannot reassign constant variable 'PI'
39 |
40 | qor(" MAX_USERS = 200")
41 | // Uncomment to see the error:
42 | // MAX_USERS = 200 // Runtime error: Cannot reassign constant variable 'MAX_USERS'
43 |
44 | qor("Constants test completed!")
45 |
--------------------------------------------------------------------------------
/public/images/sponsors/Docker.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "soplang.org",
3 | "version": "1.0.0",
4 | "description": "Official website for Soplang programming language",
5 | "scripts": {
6 | "dev": "next dev",
7 | "build": "next build",
8 | "start": "next start",
9 | "lint": "next lint"
10 | },
11 | "keywords": [
12 | "soplang",
13 | "programming language",
14 | "somali",
15 | "first somali language"
16 | ],
17 | "author": "",
18 | "license": "ISC",
19 | "dependencies": {
20 | "@radix-ui/react-separator": "^1.1.7",
21 | "@types/node": "^18.15.11",
22 | "@types/prismjs": "^1.26.5",
23 | "@types/react": "^18.0.33",
24 | "@types/react-dom": "^18.0.11",
25 | "@types/react-syntax-highlighter": "^15.5.13",
26 | "add": "^2.0.6",
27 | "autoprefixer": "^10.4.14",
28 | "class-variance-authority": "^0.7.1",
29 | "clsx": "^2.1.1",
30 | "critters": "^0.0.25",
31 | "eslint": "^8.38.0",
32 | "eslint-config-next": "^13.3.0",
33 | "lucide-react": "^0.537.0",
34 | "next": "^13.3.0",
35 | "next-themes": "^0.4.6",
36 | "postcss": "^8.4.21",
37 | "prismjs": "^1.30.0",
38 | "react": "^18.2.0",
39 | "react-dom": "^18.2.0",
40 | "react-icons": "^5.5.0",
41 | "react-syntax-highlighter": "^15.6.1",
42 | "tailwind-merge": "^3.3.1",
43 | "tailwindcss": "^3.3.1",
44 | "tailwindcss-animate": "^1.0.7",
45 | "typescript": "^5.0.4"
46 | },
47 | "devDependencies": {
48 | "prettier": "3.5.3"
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/examples/19_list_filter_complex.sop:
--------------------------------------------------------------------------------
1 | // Complex Test: List Filter (shaandhee)
2 | // Testing the shaandhee() method with different data types and conditions
3 |
4 | qor("Testing list filter (shaandhee) with complex conditions:")
5 |
6 | // Test 1: Filter numbers based on a calculation
7 | hawl is_divisible_by_three(n) {
8 | celi n % 3 == 0
9 | }
10 |
11 | teed numbers = [3, 5, 6, 9, 10, 12, 15, 18]
12 | qor("Original numbers: " + numbers)
13 | door divisible_by_three = numbers.shaandhee(is_divisible_by_three)
14 | qor("Numbers divisible by 3: " + divisible_by_three)
15 |
16 | // Test 2: Filter strings by their characteristics
17 | // In Soplang, we don't have a string length method, so we use a different approach
18 | hawl has_letter_e(s) {
19 | // This is a simple approximation since we don't have string search in Soplang
20 | celi s == "hello" || s == "welcome" || s == "greetings"
21 | }
22 |
23 | teed words = ["hello", "hi", "welcome", "bye", "greetings", "ok"]
24 | qor("Original words: " + words)
25 | door words_with_e = words.shaandhee(has_letter_e)
26 | qor("Words containing 'e': " + words_with_e)
27 |
28 | // Test 3: Filter by a more complex condition with multiple operators
29 | hawl is_special_number(n) {
30 | celi n > 10 && n % 2 == 1
31 | }
32 |
33 | teed more_numbers = [5, 8, 11, 14, 15, 18, 21]
34 | qor("More numbers: " + more_numbers)
35 | door special_numbers = more_numbers.shaandhee(is_special_number)
36 | qor("Numbers greater than 10 and odd: " + special_numbers)
37 |
38 | qor("All tests completed!")
39 |
--------------------------------------------------------------------------------
/md/01_syntax.md:
--------------------------------------------------------------------------------
1 | # Soplang Syntax
2 |
3 | Soplang syntax is designed to be clear, minimal, and intuitive for Somali speakers. It uses Somali keywords to represent familiar programming concepts, making code feel natural and readable.
4 |
5 | ---
6 |
7 | ### 🟢 Hello World
8 |
9 | ```sop
10 | qor("Hello, Adduun!")
11 | ```
12 |
13 | This is the simplest Soplang program. It uses the built-in function `qor()` to display output.
14 |
15 | ---
16 |
17 | ### 🧱 Structure
18 |
19 | Soplang programs consist of:
20 |
21 | - **Declarations** – using `door`, `abn`, `jajab`, or `madoor`
22 | - **Functions** – using `hawl`, `celi`
23 | - **Control flow** – using `haddii`, `ugudambeyn`, `celi`, etc.
24 | - **Built-ins** – like `qor()`, `gelin()`, `nooc()`
25 |
26 | Blocks are defined using curly braces `{}` and code is written line by line.
27 |
28 | ---
29 |
30 | ### 🔍 Example Program
31 |
32 | ```sop
33 | hawl salaan(magac) {
34 | qor("Asalaamu calaykum, " + magac)
35 | }
36 |
37 | door magaca = gelin("Magacaaga qor: ")
38 | salaan(magaca)
39 | ```
40 |
41 | This example reads user input and greets them. It includes:
42 |
43 | - a function definition (`hawl`)
44 | - a variable (`door`)
45 | - built-in functions (`qor`, `gelin`)
46 |
47 | ---
48 |
49 | ### 📦 File Extension
50 |
51 | Soplang source files use the `.sop` extension. You can run them with the Soplang CLI or REPL:
52 |
53 | ```bash
54 | soplang file.sop
55 | ```
56 |
57 | ---
58 |
59 | This syntax introduces the flow and feeling of Soplang: simple, expressive, and Somali-first.
60 |
--------------------------------------------------------------------------------
/examples/33_string_methods.sop:
--------------------------------------------------------------------------------
1 | // Test: String Methods
2 | // This test demonstrates string methods like qeybi() to split strings
3 |
4 | qor("Testing string methods:")
5 |
6 | // Simple string splitting example
7 | door text = "Ayaan,Cali,Zahra"
8 | teed magacyo = text.qeybi(",")
9 | qor(" Split by comma: " + magacyo)
10 |
11 | // Splitting with spaces
12 | door sentence = "Soplang waa luqad wacan"
13 | teed words = sentence.qeybi(" ")
14 | qor(" Split by space: " + words)
15 |
16 | // Handling empty strings
17 | door empty = ""
18 | teed emptyParts = empty.qeybi(",")
19 | qor(" Split empty string: " + emptyParts)
20 |
21 | // Handling delimiter not found
22 | door noDelim = "hello"
23 | teed noDelimParts = noDelim.qeybi(",")
24 | qor(" Split with no delimiter: " + noDelimParts)
25 |
26 | // Handling consecutive delimiters
27 | door consecutive = "a,,b,c,"
28 | teed consecutiveParts = consecutive.qeybi(",")
29 | qor(" Split with consecutive delimiters: " + consecutiveParts)
30 |
31 | // Using split result in loops
32 | qor("\nIterating through split results:")
33 | door csv = "1,2,3,4,5"
34 | teed numbers = csv.qeybi(",")
35 |
36 | kuceli (i 0 ilaa numbers.dherer() - 1) {
37 | qor(" Item " + i + ": " + numbers[i])
38 | }
39 |
40 | // Converting split numeric strings to numbers
41 | qor("\nConverting split strings to numbers:")
42 | kuceli (i 0 ilaa numbers.dherer() - 1) {
43 | abn num = abn(numbers[i])
44 | qor(" Number " + i + ": " + num + " (type: " + nooc(num) + ")")
45 | }
46 |
47 | qor("\nString method tests completed!")
48 |
--------------------------------------------------------------------------------
/examples/27_list_transform.sop:
--------------------------------------------------------------------------------
1 | // Test: List Transform (aaddin) Method
2 | // This test demonstrates the usage of the aaddin() method for transforming lists
3 |
4 | // Define transformation functions
5 | hawl laban(x) {
6 | celi x * 2
7 | }
8 |
9 | hawl ku_badal_qoraal(x) {
10 | celi "abn_" + x
11 | }
12 |
13 | hawl kent_juft(x) {
14 | haddii (x % 2 == 0) {
15 | celi "Juft_" + x
16 | } kale {
17 | celi "Kent_" + x
18 | }
19 | }
20 |
21 | // Let's remove the object test until we better understand Soplang's object syntax
22 | // We've successfully demonstrated the core functionality with numbers and strings
23 |
24 | qor("Testing list transform (aaddin) method:")
25 |
26 | // Create a sample list
27 | teed numbers = [1, 2, 3, 4, 5]
28 | qor("Original list: " + numbers)
29 |
30 | // Apply number transformation (doubling)
31 | teed result1 = numbers.aaddin("laban")
32 | qor("After numbers.aaddin('laban'): " + result1) // Should be [2, 4, 6, 8, 10]
33 |
34 | // Apply string transformation (adding prefix)
35 | teed result2 = numbers.aaddin("ku_badal_qoraal")
36 | qor("After numbers.aaddin('ku_badal_qoraal'): " + result2) // Should be ["abn_1", "abn_2", ...]
37 |
38 | // Apply conditional transformation (even/odd)
39 | teed result3 = numbers.aaddin("kent_juft")
40 | qor("After numbers.aaddin('kent_juft'): " + result3) // Should process even/odd numbers differently
41 |
42 | // Confirm original list is unchanged
43 | qor("Original list after transforms: " + numbers) // Should still be [1, 2, 3, 4, 5]
44 |
45 | qor("List transform test completed!")
46 |
--------------------------------------------------------------------------------
/examples/23_constant_type_check.sop:
--------------------------------------------------------------------------------
1 | // Test: Constant Type Checking
2 | // This test verifies that typed constants are properly type-checked
3 |
4 | qor("Testing constant type checking:")
5 |
6 | // Define some typed constants
7 | madoor abn MAX_COUNT = 100
8 | madoor qoraal APP_NAME = "Soplang"
9 | madoor bool IS_DEBUG = run
10 | madoor teed ALLOWED_OPTIONS = ["option1", "option2", "option3"]
11 | madoor walax CONFIG = {host: "localhost", port: 8080}
12 |
13 | qor("Checking types of constants:")
14 | qor(" MAX_COUNT: " + nooc(MAX_COUNT))
15 | qor(" APP_NAME: " + nooc(APP_NAME))
16 | qor(" IS_DEBUG: " + nooc(IS_DEBUG))
17 | qor(" ALLOWED_OPTIONS: " + nooc(ALLOWED_OPTIONS))
18 | qor(" CONFIG: " + nooc(CONFIG))
19 |
20 | // Examples of valid usage
21 | abn counter = MAX_COUNT - 50
22 | qor("Counter: " + counter)
23 |
24 | qoraal message = "Welcome to " + APP_NAME
25 | qor("Message: " + message)
26 |
27 | haddii (IS_DEBUG) {
28 | qor("Debug mode is enabled")
29 | }
30 |
31 | teed user_options = ALLOWED_OPTIONS
32 | user_options.kudar("option4") // This modifies the copy, not the constant
33 | qor("User options: " + user_options)
34 | qor("Allowed options (constant): " + ALLOWED_OPTIONS)
35 |
36 | qor("Server config: " + CONFIG.host + ":" + CONFIG.port)
37 |
38 | // For demonstration - these would cause type errors if uncommented
39 | qor("Type errors if uncommented:")
40 | qor(" // madoor abn INVALID_INT = 'not a number'")
41 | qor(" // madoor qoraal INVALID_STRING = 123")
42 | qor(" // madoor bool INVALID_BOOL = 'not a boolean'")
43 |
44 | qor("Constant type checking test completed!")
45 |
--------------------------------------------------------------------------------
/md/10_objects.md:
--------------------------------------------------------------------------------
1 | # Objects in Soplang
2 |
3 | Objects in Soplang are defined using the type `walax`. They store key-value pairs and support a set of methods to inspect, modify, and copy object data.
4 |
5 | ---
6 |
7 | ### 🧾 Declaring an Object – `walax`
8 |
9 | ```sop
10 | walax qof = {
11 | magac: "Ayaan",
12 | da: 25,
13 | shaqo: "barayaal"
14 | }
15 | ```
16 |
17 | ---
18 |
19 | ### 🔧 Core Object Methods
20 |
21 | #### `fure()` – Get Keys
22 |
23 | ```sop
24 | door keys = qof.fure()
25 | qor(keys)
26 | ```
27 |
28 | #### `qiime()` – Get Values
29 |
30 | ```sop
31 | door values = qof.qiime()
32 | qor(values)
33 | ```
34 |
35 | #### `lamaane()` – Get Key-Value Pairs
36 |
37 | ```sop
38 | door pairs = qof.lamaane()
39 | qor(pairs)
40 | ```
41 |
42 | #### `leeyahay(x)` – Has Key
43 |
44 | ```sop
45 | haddii (qof.leeyahay("magac")) {
46 | qor("Magaca wuu jiraa")
47 | }
48 | ```
49 |
50 | #### `tir(x)` – Delete Key
51 |
52 | ```sop
53 | qof.tir("shaqo")
54 | qor(qof)
55 | ```
56 |
57 | #### `kudar(obj)` – Merge/Assign
58 |
59 | ```sop
60 | walax A = {x: 1}
61 | walax B = {y: 2}
62 | walax C = A.kudar(B)
63 |
64 | qor(C) // {x: 1, y: 2}
65 | ```
66 |
67 | #### `nuqul()` – Copy
68 |
69 | ```sop
70 | walax asal = {a: 10, b: 20}
71 | walax copy = asal.nuqul()
72 | qor(copy)
73 | ```
74 |
75 | #### `nadiifi()` – Clear All Properties
76 |
77 | ```sop
78 | asal.nadiifi()
79 | qor("Cleared object: " + asal)
80 | ```
81 |
82 | ---
83 |
84 | Objects in Soplang give you a powerful way to manage named data, with methods that match familiar operations but in fully Somali terms.
85 |
--------------------------------------------------------------------------------
/examples/17_list_reverse.sop:
--------------------------------------------------------------------------------
1 | // Test: List Reverse
2 | // This test checks if the rog() method correctly reverses lists in-place
3 |
4 | qor("Testing list reverse (rog) method:")
5 |
6 | // Simple list reversal
7 | teed magacyo = ["Ayaan", "Barwaaqo", "Cali"]
8 | qor(" Original list: " + magacyo)
9 | magacyo.rog()
10 | qor(" After rog(): " + magacyo) // Should output: ["Cali", "Barwaaqo", "Ayaan"]
11 |
12 | // Reversal of a numeric list
13 | teed numbers = [1, 2, 3, 4, 5]
14 | qor(" Original numeric list: " + numbers)
15 | numbers.rog()
16 | qor(" After rog(): " + numbers) // Should output: [5, 4, 3, 2, 1]
17 |
18 | // Verify the list is mutated (same reference)
19 | teed original = [10, 20, 30]
20 | qor(" Original list: " + original)
21 | door reference = original
22 | reference.rog()
23 | qor(" After rog() via reference: " + original) // Should show the reversed list
24 | qor(" Proving it's the same reference: " + reference) // Should be identical to original
25 |
26 | // Empty list
27 | teed empty = []
28 | qor(" Empty list: " + empty)
29 | empty.rog()
30 | qor(" After rog() on empty list: " + empty) // Should still be empty
31 |
32 | // Single element list
33 | teed single = ["Solo"]
34 | qor(" Single element list: " + single)
35 | single.rog()
36 | qor(" After rog() on single element list: " + single) // Should be unchanged
37 |
38 | // Method chaining
39 | teed chain = [1, 2, 3]
40 | qor(" Method chaining:")
41 | qor(" Original list: " + chain)
42 | chain.rog().kudar(4)
43 | qor(" After rog().kudar(4): " + chain) // Should be [3, 2, 1, 4]
44 |
45 | qor("List reverse (rog) tests completed!")
46 |
--------------------------------------------------------------------------------
/examples/09_while_loops.sop:
--------------------------------------------------------------------------------
1 | // Test: While Loops
2 | // This test checks if while loops work properly
3 |
4 | qor("Testing while loops (intay):")
5 |
6 | // Simple while loop
7 | abn counter = 1
8 | qor(" Simple while loop:")
9 | intay (counter <= 5) {
10 | qor(" Counter: " + counter)
11 | counter = counter + 1
12 | }
13 |
14 | // While loop with break
15 | qor(" While loop with break (jooji):")
16 | counter = 1
17 | intay (counter <= 10) {
18 | qor(" Counter: " + counter)
19 |
20 | haddii (counter == 5) {
21 | qor(" Breaking the loop at counter = 5")
22 | jooji
23 | }
24 |
25 | counter = counter + 1
26 | }
27 |
28 | // While loop with continueA
29 | qor(" While loop with continue (soco):")
30 | counter = 0
31 | intay (counter < 5) {
32 | counter = counter + 1
33 |
34 | haddii (counter % 2 == 0) {
35 | soco
36 | }
37 |
38 | qor(" Odd counter: " + counter)
39 | }
40 |
41 | // Nested while loops
42 | qor(" Nested while loops:")
43 | abn i = 1
44 | intay (i <= 3) {
45 | qor(" Outer loop: " + i)
46 | abn j = 1
47 | intay (j <= 2) {
48 | qor(" Inner loop: " + j)
49 | j = j + 1
50 | }
51 | i = i + 1
52 | }
53 |
54 | // While loop with decimal values
55 | qor(" While loop with decimal values:")
56 | jajab x = 0.5
57 | intay (x < 3.0) {
58 | qor(" x = " + x)
59 | x = x + 0.5
60 | }
61 |
62 | // Factorial calculation using while loop
63 | abn a = 5
64 | abn factorial = 1
65 | abn n = a
66 | qor(" Factorial calculation for " + a + ":")
67 | intay (n > 0) {
68 | factorial = factorial * n
69 | n = n - 1
70 | }
71 | qor(" " + a + "! = " + factorial)
72 |
--------------------------------------------------------------------------------
/md/03_variables.md:
--------------------------------------------------------------------------------
1 | # Soplang Variables
2 |
3 | Soplang variables are declared using Somali-first keywords that reflect their role or type. These make code more expressive and localized for Somali speakers.
4 |
5 | ---
6 |
7 | ### 🟢 Dynamic Variables – `door`
8 |
9 | - `door` is short for *doorsoome*
10 | - Used for dynamically typed variables
11 |
12 | ```sop
13 | door magaca = "Aamina"
14 | door da = 19
15 | door xaqiiqo = run
16 | ```
17 |
18 | ---
19 |
20 | ### 🔵 Static Variables
21 |
22 | Static variables are explicitly typed and use specific keywords for type clarity.
23 |
24 | | Type | Keyword | Stands for | Example |
25 | |-----------|----------|--------------------|--------------------------------------|
26 | | Integer | `abn` | *abyoone* | `abn tirada = 10` |
27 | | Float | `jajab` | *jajab* | `jajab qiime = 3.14` |
28 | | String | `qoraal` | *qoraal* | `qoraal magaca = "Soplang"` |
29 | | Boolean | `bool` | *bool* | `bool sax = run` |
30 | | List | `teed` | *teed* | `teed liis = [1, 2, 3]` |
31 | | Object | `walax` | *walax* | `walax qof = {magac: "Ali"}` |
32 |
33 | ---
34 |
35 | ### 🟡 Constants – `madoor`
36 |
37 | - `madoor` is short for *madoorsoome*
38 | - Used for immutable values (constants)
39 |
40 | ```sop
41 | madoor magaca = "Soplang"
42 | madoor da: abn = 21
43 | ```
44 |
45 | Constants cannot be reassigned:
46 |
47 | ```sop
48 | madoor luqad = "Somali"
49 | luqad = "English" // ❌ Error: cannot reassign constant
50 | ```
51 |
52 | ---
53 |
54 | This section covers how to declare and use dynamic, static, and constant variables in Soplang.
55 |
--------------------------------------------------------------------------------
/scripts/generate-placeholders.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs');
2 | const path = require('path');
3 |
4 | // Create the scripts directory if it doesn't exist
5 | const scriptsDir = path.join(__dirname);
6 | if (!fs.existsSync(scriptsDir)) {
7 | fs.mkdirSync(scriptsDir, { recursive: true });
8 | }
9 |
10 | // Create the testimonials directory if it doesn't exist
11 | const testimonialsDir = path.join(__dirname, '../public/images/testimonials');
12 | if (!fs.existsSync(testimonialsDir)) {
13 | fs.mkdirSync(testimonialsDir, { recursive: true });
14 | }
15 |
16 | // Generate SVG placeholder images
17 | const generatePlaceholderSVG = (name, color) => {
18 | const initials = name.split(' ')
19 | .map(part => part[0])
20 | .join('')
21 | .toUpperCase();
22 |
23 | return `
24 |
25 |
26 | ${initials}
27 |
28 | `;
29 | };
30 |
31 | // Create placeholder images for our testimonials
32 | const testimonials = [
33 | { name: 'Mr Sharafdin', color: '#3F72AF' }, // Primary color
34 | { name: 'Omar Tood', color: '#5E9A78' }, // Secondary color
35 | { name: 'Ismail Ainte', color: '#6B5B95' } // Another complementary color
36 | ];
37 |
38 | testimonials.forEach(person => {
39 | const fileName = person.name.toLowerCase().replace(' ', '');
40 | const svgContent = generatePlaceholderSVG(person.name, person.color);
41 | fs.writeFileSync(path.join(testimonialsDir, `${fileName}.svg`), svgContent);
42 | console.log(`Created placeholder for ${person.name}`);
43 | });
44 |
45 | console.log('All placeholder images generated successfully!');
--------------------------------------------------------------------------------
/examples/04_arithmetic_operators.sop:
--------------------------------------------------------------------------------
1 | // Test: Arithmetic Operators
2 | // This test checks if arithmetic operators work properly
3 |
4 | qor("Testing arithmetic operators:")
5 |
6 | // Integer operations
7 | qor("Integer operations:")
8 | abn a = 15
9 | abn b = 5
10 | qor(" a = " + a + ", b = " + b)
11 |
12 | // Basic operations with integers
13 | qor(" Addition (a + b): " + (a + b))
14 | qor(" Subtraction (a - b): " + (a - b))
15 | qor(" Multiplication (a * b): " + (a * b))
16 | qor(" Division (a / b): " + (a / b))
17 | qor(" Modulus (a % b): " + (a % b))
18 |
19 | // Test with negative integers
20 | abn negative = -10
21 | qor(" negative = " + negative)
22 | qor(" Addition with negative (a + negative): " + (a + negative))
23 | qor(" Negative multiplication (negative * b): " + (negative * b))
24 |
25 | // Decimal operations
26 | qor("\nDecimal operations:")
27 | jajab x = 15.5
28 | jajab y = 5.25
29 | qor(" x = " + x + ", y = " + y)
30 |
31 | // Basic operations with decimals
32 | qor(" Addition (x + y): " + (x + y))
33 | qor(" Subtraction (x - y): " + (x - y))
34 | qor(" Multiplication (x * y): " + (x * y))
35 | qor(" Division (x / y): " + (x / y))
36 |
37 | // Mixed operations (integers and decimals)
38 | qor("\nMixed integer and decimal operations:")
39 | qor(" Integer + Decimal (a + y): " + (a + y))
40 | qor(" Decimal * Integer (x * b): " + (x * b))
41 |
42 | // Operator precedence
43 | qor("\nOperator precedence:")
44 | qor(" Operator precedence (2 + 3 * 4): " + (2 + 3 * 4))
45 | qor(" Using parentheses ((2 + 3) * 4): " + ((2 + 3) * 4))
46 |
47 | // Complex expressions
48 | abn complex_int = (a + b) * 2 - 10 / 2
49 | jajab complex_dec = (x + y) * 2.5 - 10.5 / 2.1
50 | qor("\nComplex expressions:")
51 | qor(" Integer expression ((a + b) * 2 - 10 / 2): " + complex_int)
52 | qor(" Decimal expression ((x + y) * 2.5 - 10.5 / 2.1): " + complex_dec)
53 |
--------------------------------------------------------------------------------
/src/app/about/quotes/page.tsx:
--------------------------------------------------------------------------------
1 | import { Metadata } from "next";
2 | import Image from "next/image";
3 | import { notFound } from "next/navigation";
4 |
5 | export const metadata: Metadata = {
6 | title: "Quotes - Soplang",
7 | description:
8 | "What developers and companies are saying about Soplang programming language.",
9 | };
10 |
11 | const quotes = [
12 | {
13 | text: "Soplang has transformed how we build our backend services. Its simplicity and performance are unmatched.",
14 | author: "Mr Sharafdin",
15 | role: "Senior Software Engineer",
16 | company: "Tech Solutions Inc.",
17 | image: "/images/testimonials/sharafdin.jpg",
18 | },
19 | {
20 | text: "The learning curve is incredibly smooth. Soplang makes complex programming concepts accessible to everyone.",
21 | author: "Omar Tood",
22 | role: "Soplang Creator",
23 | company: "Innovation Labs",
24 | image: "/images/testimonials/omar.jpg",
25 | },
26 | {
27 | text: "We've seen a 40% increase in development speed since switching to Soplang. It's now our go-to language for new projects.",
28 | author: "Ismail Ainte",
29 | role: "CTO",
30 | company: "StartUp Hub",
31 | image: "/images/testimonials/ismail.jpg",
32 | },
33 | ];
34 |
35 | const featuredQuotes = [
36 | {
37 | text: "Soplang represents the future of programming languages - simple, fast, and developer-friendly.",
38 | source: "TechDaily",
39 | link: "https://techdaily.com/soplang-review",
40 | },
41 | {
42 | text: "A game-changer in the programming world. Soplang combines simplicity with powerful performance, making it accessible to Somali developers worldwide.",
43 | source: "CodeMagazine",
44 | link: "https://codemagazine.com/soplang",
45 | },
46 | ];
47 |
48 | export default function AboutQuotesPage() {
49 | // Make this page inaccessible
50 | notFound();
51 | }
52 |
--------------------------------------------------------------------------------
/examples/06_logical_operators.sop:
--------------------------------------------------------------------------------
1 | // Test: Logical Operators
2 | // This test checks if logical operators work properly
3 |
4 | qor("Testing logical operators:")
5 |
6 | // Boolean values
7 | bool c = been
8 | bool d = run
9 | qor(" c = " + c + ", d = " + d)
10 |
11 | // Basic logical operations
12 | qor(" AND (c && d): " + (c && d))
13 | qor(" OR (c || d): " + (c || d))
14 | qor(" NOT (!c): " + (!c))
15 | qor(" NOT (!d): " + (!d))
16 |
17 | // Compound expressions
18 | qor(" Compound AND (c && !d): " + (c && !d))
19 | qor(" Compound OR (!c || d): " + (!c || d))
20 | qor(" Complex expression (c && (d || !d)): " + (c && (d || !d)))
21 | qor(" Complex expression ((c || d) && (c || !d)): " + ((c || d) && (c || !d)))
22 |
23 | // Using integer values in logical operations
24 | abn x = 10
25 | abn y = 20
26 | qor("\nLogical operations with integers:")
27 | qor(" x = " + x + ", y = " + y)
28 | qor(" Comparison in logical expression ((x > 5) && (y < 30)): " + ((x > 5) && (y < 30)))
29 | qor(" Comparison in logical expression ((x > 15) || (y < 30)): " + ((x > 15) || (y < 30)))
30 |
31 | // Using decimal values in logical operations
32 | jajab a = 10.5
33 | jajab b = 20.25
34 | qor("\nLogical operations with decimals:")
35 | qor(" a = " + a + ", b = " + b)
36 | qor(" Comparison in logical expression ((a > 5.5) && (b < 30.5)): " + ((a > 5.5) && (b < 30.5)))
37 | qor(" Comparison in logical expression ((a > 15.5) || (b < 30.5)): " + ((a > 15.5) || (b < 30.5)))
38 |
39 | // Mixed integer and decimal comparisons
40 | qor("\nLogical operations with mixed types:")
41 | qor(" Integer vs. Decimal ((x < a) && (y > b)): " + ((x < a) && (y > b)))
42 | qor(" Integer vs. Decimal ((x > a) || (y > b)): " + ((x > a) || (y > b)))
43 |
44 | // Assignment of logical operations
45 | door result = ((x < y) && (c || d))
46 | qor("\nAssignment of logical operation (result = (x < y) && (c || d)): " + result)
47 |
--------------------------------------------------------------------------------
/src/app/not-found.tsx:
--------------------------------------------------------------------------------
1 | import Link from "next/link";
2 |
3 | export default function NotFound() {
4 | return (
5 |
6 |
7 |
404
8 |
9 | Page Not Found
10 |
11 |
12 | The page you are looking for doesn't exist or has been moved.
13 |
14 |
15 |
16 | Return to Home
17 |
18 |
19 | View Documentation
20 |
21 |
22 |
23 |
24 |
25 | Looking for something specific?
26 |
27 |
28 |
29 | Documentation
30 |
31 |
32 | Blog
33 |
34 |
35 | Downloads
36 |
37 |
38 | Community
39 |
40 |
41 | About
42 |
43 |
44 |
45 |
46 |
47 | );
48 | }
49 |
--------------------------------------------------------------------------------
/examples/11_list_operations.sop:
--------------------------------------------------------------------------------
1 | // Test: List Operations
2 | // This test checks if list operations work properly
3 |
4 | qor("Testing list operations:")
5 |
6 | // Creating lists
7 | teed empty_list = []
8 | teed numbers = [10, 20, 30, 40, 50]
9 | teed mixed = [1, "two", been, [1, 2], {name: "something"}]
10 |
11 | qor(" Empty list: " + empty_list)
12 | qor(" Numbers list: " + numbers)
13 | qor(" Mixed list: " + mixed)
14 |
15 | // Accessing elements
16 | qor(" First element of numbers: " + numbers[0])
17 | qor(" Third element of numbers: " + numbers[2])
18 | qor(" Last element of numbers: " + numbers[4])
19 |
20 | // Modifying elements
21 | numbers[1] = 25
22 | qor(" After changing second element: " + numbers)
23 |
24 | // List length
25 | qor(" List length: " + numbers.dherer())
26 |
27 | // Push operation
28 | numbers.kudar(60)
29 | qor(" After push: " + numbers)
30 | numbers.kudar(70)
31 | qor(" After another push: " + numbers)
32 |
33 | // Pop operation
34 | door popped = numbers.kasaar()
35 | qor(" Popped value: " + popped)
36 | qor(" List after pop: " + numbers)
37 |
38 | // Nested list access
39 | teed nested = [[1, 2], [3, 4]]
40 | qor(" Nested list: " + nested)
41 | qor(" Accessing nested element [1][0]: " + nested[1][0])
42 |
43 | // List iteration
44 | qor(" List iteration using for loop:")
45 | kuceli (i 0 ilaa numbers.dherer() - 1) {
46 | qor(" Element " + i + ": " + numbers[i])
47 | }
48 |
49 | // List concatenation
50 | teed list1 = [1, 2, 3]
51 | teed list2 = [4, 5, 6]
52 | teed combined = list1.kudar(list2)
53 | qor(" List1: " + list1)
54 | qor(" List2: " + list2)
55 | qor(" Combined list: " + combined)
56 |
57 | // Check if element exists in list
58 | abn search_value = 30
59 | bool contains = numbers.leeyahay(search_value)
60 | qor(" Does numbers contain " + search_value + "? " + contains)
61 |
62 | search_value = 100
63 | contains = numbers.leeyahay(search_value)
64 | qor(" Does numbers contain " + search_value + "? " + contains)
65 |
--------------------------------------------------------------------------------
/examples/16_list_copy.sop:
--------------------------------------------------------------------------------
1 | // Test: List Copy Operations
2 | // This test demonstrates the nuqul() method for making shallow copies of lists
3 |
4 | qor("Testing list copy (nuqul) method:")
5 |
6 | // Create an original list
7 | teed asalka = [1, 2, 3]
8 | qor(" Original list (asalka): " + asalka)
9 |
10 | // Create a copy using nuqul()
11 | teed nuqul_list = asalka.nuqul()
12 | qor(" Copied list (nuqul_list): " + nuqul_list)
13 |
14 | // Modify the original list
15 | asalka.kudar(4)
16 | qor(" Original list after modification: " + asalka)
17 | qor(" Copied list after original was modified: " + nuqul_list)
18 |
19 | // Verify that the lists are separate objects
20 | qor("Verifying that the copy is independent from the original:")
21 | qor(" asalka == nuqul_list: " + (asalka == nuqul_list)) // Content comparison
22 | qor(" After adding an element to the copy:")
23 | nuqul_list.kudar(5)
24 | qor(" Original list: " + asalka)
25 | qor(" Modified copy: " + nuqul_list)
26 |
27 | // Test with nested structures (shallow copy behavior)
28 | qor("Testing shallow copy behavior with nested lists:")
29 | teed nested = [[10, 20], [30, 40]]
30 | teed nested_copy = nested.nuqul()
31 | qor(" Original nested list: " + nested)
32 | qor(" Nested list copy: " + nested_copy)
33 |
34 | // Modify a nested element (should affect both lists since it's a shallow copy)
35 | nested[0][0] = 15
36 | qor(" After modifying a nested element (nested[0][0] = 15):")
37 | qor(" Original nested list: " + nested)
38 | qor(" Nested list copy: " + nested_copy)
39 |
40 | // Modify the outer structure (should not affect the copy)
41 | nested.kudar([50, 60])
42 | qor(" After adding a new nested list to the original:")
43 | qor(" Original nested list: " + nested)
44 | qor(" Nested list copy: " + nested_copy)
45 | qor(" Notice: The nested copy doesn't contain the [50, 60] element added to the original")
46 |
47 | qor("The nuqul() method successfully creates a shallow copy that is independent at the top level.")
48 |
--------------------------------------------------------------------------------
/md/07_loops.md:
--------------------------------------------------------------------------------
1 | # Loops in Soplang
2 |
3 | Soplang supports two distinct types of loops:
4 |
5 | - `intay (condition)` → while loop
6 | - `kuceli (start ilaa end)` → for loop
7 |
8 | It also provides `jooji` (break) and `soco` (continue) for fine control.
9 |
10 | ---
11 |
12 | ### 🔁 While Loop – `intay`
13 |
14 | Repeats a block of code as long as the condition is true:
15 |
16 | ```sop
17 | abn i = 1
18 | intay (i <= 5) {
19 | qor("i = " + i)
20 | i = i + 1
21 | }
22 | ```
23 |
24 | Supports break and continue:
25 |
26 | ```sop
27 | intay (i <= 10) {
28 | haddii (i == 6) {
29 | jooji
30 | }
31 | i = i + 1
32 | }
33 | ```
34 |
35 | ---
36 |
37 | ### 🔁 For Loop – `kuceli`
38 |
39 | ```sop
40 | kuceli (i 1 ilaa 5) {
41 | qor("Tirada: " + i)
42 | }
43 | ```
44 |
45 | With step:
46 |
47 | ```sop
48 | kuceli (j 2 ilaa 10 :: 2) {
49 | qor("Step: " + j)
50 | }
51 | ```
52 |
53 | ---
54 |
55 | ### 🔁 Loop Over List
56 |
57 | ```sop
58 | teed numbers = [10, 20, 30]
59 | kuceli (i 0 ilaa numbers.dherer() - 1) {
60 | qor("Element " + i + ": " + numbers[i])
61 | }
62 | ```
63 |
64 | ---
65 |
66 | ### 🔁 Nested Loops
67 |
68 | ```sop
69 | kuceli (i 1 ilaa 3) {
70 | intay (i > 0) {
71 | qor("Nested example")
72 | jooji
73 | }
74 | }
75 | ```
76 |
77 | ---
78 |
79 | ### 🔁 Factorial with While
80 |
81 | ```sop
82 | abn a = 5
83 | abn result = 1
84 | abn n = a
85 |
86 | intay (n > 0) {
87 | result = result * n
88 | n = n - 1
89 | }
90 | qor(result)
91 | ```
92 |
93 | ---
94 |
95 | ### ✅ Summary
96 |
97 | | Keyword | Meaning |
98 | |-------------|-----------------|
99 | | `intay` | while loop |
100 | | `kuceli` | for loop |
101 | | `jooji` | break |
102 | | `soco` | continue |
103 |
104 | Soplang loops support both structured iteration and conditional repetition.
105 |
--------------------------------------------------------------------------------
/examples/34_string_contains.sop:
--------------------------------------------------------------------------------
1 | // Test: String Contains Method
2 | // This test demonstrates leeyahay() to check for substrings within strings
3 |
4 | qor("Testing string contains (leeyahay) method:")
5 |
6 | // Basic substring check
7 | door magac = "Barwaaqo"
8 | door match1 = magac.leeyahay("waa") // Should be true (run)
9 | door match2 = magac.leeyahay("bilow") // Should be false (been)
10 |
11 | qor("Basic tests:")
12 | qor(" String: " + magac)
13 | qor(" Has 'waa': " + match1)
14 | qor(" Has 'bilow': " + match2)
15 |
16 | // Case sensitivity test
17 | door sentence = "Soplang waa luqad wacan"
18 | door match3 = sentence.leeyahay("waa") // Should be true
19 | door match4 = sentence.leeyahay("WAA") // Should be false (case-sensitive)
20 |
21 | qor("Case sensitivity:")
22 | qor(" String: " + sentence)
23 | qor(" Has 'waa': " + match3)
24 | qor(" Has 'WAA': " + match4)
25 |
26 | // Empty string test
27 | door empty = ""
28 | door match5 = magac.leeyahay("") // Should be true
29 | door match6 = empty.leeyahay("") // Should be true
30 | door match7 = empty.leeyahay("test") // Should be false
31 |
32 | qor("Empty string tests:")
33 | qor(" Empty string contains '': " + match6)
34 | qor(" Normal string contains '': " + match5)
35 | qor(" Empty string contains 'test': " + match7)
36 |
37 | // Position tests
38 | door match8 = sentence.leeyahay("Soplang") // At start
39 | door match9 = sentence.leeyahay("wacan") // At end
40 |
41 | qor("Position tests:")
42 | qor(" Starts with 'Soplang': " + match8)
43 | qor(" Ends with 'wacan': " + match9)
44 |
45 | // Practical application
46 | door email = "user@example.com"
47 | door valid_email = email.leeyahay("@")
48 |
49 | qor("Practical application:")
50 | qor(" Email: " + email)
51 | qor(" Contains '@': " + valid_email)
52 |
53 | haddii (valid_email) {
54 | qor(" Email format is valid")
55 | } ugudambeyn {
56 | qor(" Email format is invalid - missing @")
57 | }
58 |
59 | qor("\nString contains tests completed!")
60 |
--------------------------------------------------------------------------------
/md/04_type_conversion.md:
--------------------------------------------------------------------------------
1 | # Type Conversion in Soplang
2 |
3 | Soplang supports built-in conversion between types using Somali-first function names. These allow you to safely convert values between integers, strings, decimals, and booleans.
4 |
5 | ---
6 |
7 | ### 🧪 Type Checking – `nooc()`
8 |
9 | Use `nooc()` to check the type of any value:
10 |
11 | ```sop
12 | door natiijo = nooc(42) // "abn"
13 | door natiijo2 = nooc("abc") // "qoraal"
14 | door natiijo3 = nooc(3.14) // "jajab"
15 | ```
16 |
17 | ---
18 |
19 | ### 🔁 Type Conversion Functions
20 |
21 | | Conversion | Function | Example |
22 | |--------------------|--------------|----------------------------------|
23 | | Int → String | `qoraal()` | `qoraal(42)` |
24 | | String → Int | `abn()` | `abn("123")` |
25 | | Float → String | `qoraal()` | `qoraal(3.14)` |
26 | | String → Float | `jajab()` | `jajab("3.14")` |
27 | | Int → Float | `jajab()` | `jajab(5)` |
28 | | Float → Int | `abn()` | `abn(4.9)` → `4` (truncates) |
29 | | Any → Bool | `bool()` | `bool(1)` → `run`, `bool(0)` → `been` |
30 |
31 | ---
32 |
33 | ### 📌 Example
34 |
35 | ```sop
36 | // From: 13_type_conversion.sop
37 |
38 | // Integer to string
39 | abn int_value = 42
40 | qoraal int_str = qoraal(int_value)
41 | qor("Integer to string: " + int_str + " (Type: " + nooc(int_str) + ")")
42 |
43 | // String to decimal
44 | qoraal decimal_string = "3.14159"
45 | jajab converted_decimal = jajab(decimal_string)
46 | qor("String to decimal: " + converted_decimal + " (Type: " + nooc(converted_decimal) + ")")
47 |
48 | // Decimal to integer
49 | jajab decimal_num = 42.75
50 | abn int_from_decimal = abn(decimal_num)
51 | qor("Decimal to integer (truncation): " + int_from_decimal)
52 | ```
53 |
54 | ---
55 |
56 | These conversion functions are essential for building reliable input-handling logic in Soplang.
57 |
--------------------------------------------------------------------------------
/examples/18_list_sort.sop:
--------------------------------------------------------------------------------
1 | // Test: List Sort
2 | // This test checks if the habee() method correctly sorts lists in-place
3 |
4 | qor("Testing list sort (habee) method:")
5 |
6 | // Simple list sorting (numbers)
7 | teed abnooyin = [5, 1, 3, 4, 2]
8 | qor(" Original number list: " + abnooyin)
9 | abnooyin.habee()
10 | qor(" After habee(): " + abnooyin) // Should output: [1, 2, 3, 4, 5]
11 |
12 | // Sorting strings (alphabetical order)
13 | teed magacyo = ["Zaynab", "Cabdi", "Faadumo", "Axmed", "Xaliimo"]
14 | qor(" Original name list: " + magacyo)
15 | magacyo.habee()
16 | qor(" After habee(): " + magacyo) // Should output sorted alphabetically
17 |
18 | // Verify the list is mutated (same reference)
19 | teed original = [30, 10, 20]
20 | qor(" Original list: " + original)
21 | door reference = original
22 | reference.habee()
23 | qor(" After habee() via reference: " + original) // Should show the sorted list
24 | qor(" Proving it's the same reference: " + reference) // Should be identical to original
25 |
26 | // Empty list
27 | teed empty = []
28 | qor(" Empty list: " + empty)
29 | empty.habee()
30 | qor(" After habee() on empty list: " + empty) // Should still be empty
31 |
32 | // Single element list
33 | teed single = ["Solo"]
34 | qor(" Single element list: " + single)
35 | single.habee()
36 | qor(" After habee() on single element list: " + single) // Should be unchanged
37 |
38 | // Method chaining
39 | teed chain = [3, 1, 2]
40 | qor(" Method chaining:")
41 | qor(" Original list: " + chain)
42 | chain.habee().kudar(4)
43 | qor(" After habee().kudar(4): " + chain) // Should be [1, 2, 3, 4]
44 |
45 | // Mixed types list - should raise error when uncommented
46 | // teed mixed = [5, "a", 3, "b"]
47 | // mixed.habee() // This would cause a runtime error
48 |
49 | // List with decimal numbers
50 | teed decimals = [3.14, 1.5, 2.71, 0.99]
51 | qor(" Decimal numbers list: " + decimals)
52 | decimals.habee()
53 | qor(" After habee(): " + decimals) // Should output sorted decimal numbers
54 |
55 | qor("List sort (habee) tests completed!")
56 |
--------------------------------------------------------------------------------
/md/06_control_flow.md:
--------------------------------------------------------------------------------
1 | # Control Flow in Soplang
2 |
3 | Soplang provides conditional execution using Somali keywords to make logic clear and expressive.
4 |
5 | ---
6 |
7 | ### 🧠 If Statements – `haddii`, `haddii_kale`, `ugudambeyn`
8 |
9 | These are equivalent to `if`, `else if`, and `else` in other languages.
10 |
11 | ```sop
12 | abn da = 17
13 |
14 | haddii (da >= 18) {
15 | qor("Waad qaan gaadhay")
16 | } haddii_kale (da >= 13) {
17 | qor("Waxaad tahay dhallinyaro")
18 | } ugudambeyn {
19 | qor("Waad yar tahay")
20 | }
21 | ```
22 |
23 | Each block is enclosed in `{}`. You can nest or chain as needed.
24 |
25 | ---
26 |
27 | ### 🚦 Boolean Conditions
28 |
29 | Use `bool` type expressions with comparison or logic operators.
30 |
31 | ```sop
32 | abn x = 4
33 | abn y = 9
34 |
35 | haddii (x < y && y < 10) {
36 | qor("Shuruudaha waa sax")
37 | }
38 | ```
39 |
40 | You can also negate a condition with `!`:
41 |
42 | ```sop
43 | haddii (!(x == y)) {
44 | qor("Qiimuhu ma sina")
45 | }
46 | ```
47 |
48 | ---
49 |
50 | ### ✅ Summary
51 |
52 | | Keyword | Meaning |
53 | |------------------|------------------|
54 | | `haddii` | if |
55 | | `haddii_kale` | else if |
56 | | `ugudambeyn` | else |
57 |
58 | Control flow in Soplang follows a readable Somali-first structure.
59 |
60 |
61 | ---
62 |
63 | ### 🔄 Switch-Case – `dooro` and `xaalad`
64 |
65 | Soplang includes switch-case logic using:
66 |
67 | - `dooro` → switch expression
68 | - `xaalad` → case condition
69 | - `ugudambeyn` → default
70 |
71 | ```sop
72 | qoraal maalinta = "Jimce"
73 |
74 | dooro (maalinta) {
75 | xaalad "Isniin" {
76 | qor("Todobaad cusub")
77 | }
78 | xaalad "Jimce" {
79 | qor("Waqti nasasho")
80 | }
81 | ugudambeyn {
82 | qor("Maalin kale")
83 | }
84 | }
85 | ```
86 |
87 | This is useful for clear multi-branch logic based on values.
88 |
89 | ---
90 |
91 | ### 🔁 Combined Usage
92 |
93 | You can mix if/else and switch for complex logic in a readable way.
94 |
--------------------------------------------------------------------------------
/examples/35_math_floor.sop:
--------------------------------------------------------------------------------
1 | // Test: Math Floor Function (daji)
2 | // This test demonstrates the daji() function which rounds down to the nearest integer
3 |
4 | qor("Testing math floor function (daji):")
5 |
6 | // Basic positive numbers
7 | qor("\nPositive numbers:")
8 | qor(" daji(3.8) = " + daji(3.8)) // Should be 3
9 | qor(" daji(5.1) = " + daji(5.1)) // Should be 5
10 | qor(" daji(7.999) = " + daji(7.999)) // Should be 7
11 |
12 | // Integers (should remain the same)
13 | qor("\nIntegers:")
14 | qor(" daji(5) = " + daji(5)) // Should be 5
15 | qor(" daji(0) = " + daji(0)) // Should be 0
16 |
17 | // Negative numbers (important edge case!)
18 | qor("\nNegative numbers:")
19 | qor(" daji(-2.4) = " + daji(-2.4)) // Should be -3
20 | qor(" daji(-1.01) = " + daji(-1.01)) // Should be -2
21 | qor(" daji(-5.9) = " + daji(-5.9)) // Should be -6
22 |
23 | // Edge cases
24 | qor("\nEdge cases:")
25 | qor(" daji(0.1) = " + daji(0.1)) // Should be 0
26 | qor(" daji(-0.1) = " + daji(-0.1)) // Should be -1
27 | qor(" daji(0.999) = " + daji(0.999)) // Should be 0
28 |
29 | // Dynamic variables
30 | qor("\nWith variables:")
31 | door x = 4.7
32 | door y = -3.2
33 | qor(" x = " + x)
34 | qor(" y = " + y)
35 | qor(" daji(x) = " + daji(x)) // Should be 4
36 | qor(" daji(y) = " + daji(y)) // Should be -4
37 |
38 | // Practical examples
39 | qor("\nPractical examples:")
40 |
41 | // Example: calculating how many whole days in a number of hours
42 | door hours = 50.5
43 | door days = daji(hours / 24)
44 | qor(" " + hours + " hours = " + days + " whole days")
45 |
46 | // Example: calculating how many full pages needed for n items with k items per page
47 | door items = 27
48 | door itemsPerPage = 5
49 | door remain = items % itemsPerPage
50 | door extra = 0
51 |
52 | haddii (remain > 0) {
53 | extra = 1
54 | }
55 |
56 | door pages = daji(items / itemsPerPage) + extra
57 | qor(" " + items + " items with " + itemsPerPage + " per page = " + pages + " pages")
58 |
59 | qor("\nMath floor tests completed!")
60 |
--------------------------------------------------------------------------------
/examples/07_conditional_statements.sop:
--------------------------------------------------------------------------------
1 | // Test: Conditional Statements
2 | // This test checks if conditional statements work properly
3 |
4 | qor("Testing conditional statements (haddii):")
5 |
6 | // Simple if statement
7 | abn age = 20
8 | qor(" age = " + age)
9 |
10 | qor(" Simple if statement:")
11 | haddii (age >= 18) {
12 | qor(" Person is an adult")
13 | }
14 |
15 | // If-else statement
16 | qor(" If-else statement:")
17 | haddii (age >= 21) {
18 | qor(" Person can drink alcohol")
19 | } ugudambeyn {
20 | qor(" Person cannot drink alcohol")
21 | }
22 |
23 | // If-else if-else statement
24 | abn score = 85
25 | qor(" score = " + score)
26 | qor(" If-else if-else statement:")
27 | haddii (score >= 90) {
28 | qor(" Grade: A")
29 | } haddii_kale (score >= 80) {
30 | qor(" Grade: B")
31 | } haddii_kale (score >= 70) {
32 | qor(" Grade: C")
33 | } haddii_kale (score >= 60) {
34 | qor(" Grade: D")
35 | } ugudambeyn {
36 | qor(" Grade: F")
37 | }
38 |
39 | // Nested if statements
40 | qor(" Nested if statements:")
41 | haddii (age >= 16) {
42 | qor(" Person can drive")
43 | haddii (age >= 18) {
44 | qor(" Person can vote")
45 | haddii (age >= 21) {
46 | qor(" Person can drink alcohol")
47 | }
48 | }
49 | }
50 |
51 | // Using logical operators in conditions
52 | abn x = 10
53 | abn y = 20
54 | qor(" x = " + x + ", y = " + y)
55 |
56 | qor(" Using AND (&&) operator:")
57 | haddii (x > 5 && y < 30) {
58 | qor(" Both conditions are true")
59 | }
60 |
61 | qor(" Using OR (||) operator:")
62 | haddii (x > 15 || y > 15) {
63 | qor(" At least one condition is true")
64 | }
65 |
66 | // Testing with decimal values
67 | jajab temperature = 37.5
68 | qor(" temperature = " + temperature)
69 |
70 | qor(" Testing with decimal values:")
71 | haddii (temperature > 38.0) {
72 | qor(" Person has a fever")
73 | } haddii_kale (temperature >= 37.5) {
74 | qor(" Person has a slight temperature")
75 | } ugudambeyn {
76 | qor(" Person's temperature is normal")
77 | }
78 |
--------------------------------------------------------------------------------
/scripts/generate-news-images.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs');
2 | const path = require('path');
3 |
4 | // Create the blog images directory if it doesn't exist
5 | const blogImagesDir = path.join(__dirname, '../public/images/blog');
6 | if (!fs.existsSync(blogImagesDir)) {
7 | fs.mkdirSync(blogImagesDir, { recursive: true });
8 | }
9 |
10 | // Generate SVG placeholder images for news items
11 | const generateNewsImageSVG = (title, color) => {
12 | // Create a simplified title for the image
13 | const simplifiedTitle = title.split(':')[0].trim();
14 |
15 | return `
16 |
17 |
18 | ${simplifiedTitle}
19 |
20 |
21 | Soplang News
22 |
23 | `;
24 | };
25 |
26 | // News items that need images
27 | const newsItems = [
28 | { id: 'soplang-2.0', title: 'Announcing Soplang 2.0', color: '#3F72AF' },
29 | { id: 'community-milestone', title: 'Community Milestone', color: '#5E9A78' },
30 | { id: 'university-adoption', title: 'University Adoption', color: '#6B5B95' },
31 | { id: 'hackathon', title: 'Soplang Hackathon', color: '#E84A5F' },
32 | { id: 'release-1.5.0', title: 'Soplang 1.5.0 Release', color: '#3F72AF' },
33 | { id: 'enterprise-adoption', title: 'Enterprise Adoption', color: '#5E9A78' },
34 | { id: 'learning-resources', title: 'Learning Resources', color: '#6B5B95' },
35 | { id: 'community-contributions', title: 'Community Contributions', color: '#E84A5F' },
36 | ];
37 |
38 | // Generate images for each news item
39 | newsItems.forEach(item => {
40 | const svgContent = generateNewsImageSVG(item.title, item.color);
41 | fs.writeFileSync(path.join(blogImagesDir, `${item.id}.svg`), svgContent);
42 | console.log(`Created placeholder for ${item.title}`);
43 | });
44 |
45 | console.log('All news images generated successfully!');
--------------------------------------------------------------------------------
/examples/21_practical_constants.sop:
--------------------------------------------------------------------------------
1 | // Test: Practical Constants
2 | // This test demonstrates practical uses of constants in a small application
3 |
4 | qor("Practical uses of constants (madoor):")
5 |
6 | // Application configuration constants
7 | madoor qoraal APP_VERSION = "1.0.0"
8 | madoor qoraal API_ENDPOINT = "https://api.example.com/v1"
9 | madoor abn TIMEOUT_MS = 5000
10 | madoor abn MAX_RETRIES = 3
11 | madoor abn MAX_ITEMS_PER_PAGE = 25
12 |
13 | // Math constants
14 | madoor jajab PI = 3.14159
15 | madoor jajab E = 2.71828
16 |
17 | // Status codes
18 | madoor abn STATUS_OK = 200
19 | madoor abn STATUS_NOT_FOUND = 404
20 | madoor abn STATUS_ERROR = 500
21 |
22 | qor("Application Configuration:")
23 | qor(" App Version: " + APP_VERSION)
24 | qor(" API Endpoint: " + API_ENDPOINT)
25 | qor(" Timeout: " + TIMEOUT_MS + "ms")
26 | qor(" Max Retries: " + MAX_RETRIES)
27 | qor(" Items Per Page: " + MAX_ITEMS_PER_PAGE)
28 |
29 | // Simulate a function that uses these constants
30 | hawl make_api_request(endpoint, timeout_ms) {
31 | qor("Simulating API request:")
32 | qor(" Endpoint: " + endpoint)
33 | qor(" Timeout: " + timeout_ms + "ms")
34 | qor(" Max Retries: " + MAX_RETRIES)
35 |
36 | // Simulate response
37 | qor(" Response Status: " + STATUS_OK)
38 |
39 | celi STATUS_OK
40 | }
41 |
42 | // Use the constants in calculations and functions
43 | abn response = make_api_request(API_ENDPOINT, TIMEOUT_MS)
44 |
45 | // Calculate area and volume using constants
46 | jajab radius = 10
47 | jajab area = PI * radius * radius
48 | jajab volume = (4/3) * PI * radius * radius * radius
49 |
50 | qor("Geometric Calculations (radius = " + radius + "):")
51 | qor(" Circle Area: " + area)
52 | qor(" Sphere Volume: " + volume)
53 |
54 | // Simulate pagination
55 | abn total_items = 127
56 | abn total_pages = (total_items + MAX_ITEMS_PER_PAGE - 1) / MAX_ITEMS_PER_PAGE // Ceiling division
57 |
58 | qor("Pagination:")
59 | qor(" Total Items: " + total_items)
60 | qor(" Items Per Page: " + MAX_ITEMS_PER_PAGE)
61 | qor(" Total Pages: " + total_pages)
62 |
63 | qor("Practical constants test completed!")
64 |
--------------------------------------------------------------------------------
/temp_backup/src/app/layout.tsx:
--------------------------------------------------------------------------------
1 | import Footer from "@/components/Footer";
2 | import Navbar from "@/components/Navbar";
3 | import "@/styles/globals.css";
4 | import type { Metadata } from "next";
5 | import { ThemeProvider } from "next-themes";
6 | import { Inter } from "next/font/google";
7 |
8 | const inter = Inter({ subsets: ["latin"] });
9 |
10 | export const metadata: Metadata = {
11 | title: "Soplang - A Python-inspired Programming Language",
12 | description:
13 | "Soplang is a modern, intuitive programming language inspired by Python, designed for simplicity and usability.",
14 | keywords: [
15 | "Soplang",
16 | "programming language",
17 | "Python-inspired",
18 | "coding",
19 | "development",
20 | ],
21 | openGraph: {
22 | title: "Soplang - A Python-inspired Programming Language",
23 | description:
24 | "Soplang is a modern, intuitive programming language inspired by Python, designed for simplicity and usability.",
25 | url: "https://soplang.org",
26 | siteName: "Soplang",
27 | images: [
28 | {
29 | url: "/images/og-image.png",
30 | width: 1200,
31 | height: 630,
32 | alt: "Soplang Programming Language",
33 | },
34 | ],
35 | locale: "en_US",
36 | type: "website",
37 | },
38 | twitter: {
39 | card: "summary_large_image",
40 | title: "Soplang - A Python-inspired Programming Language",
41 | description:
42 | "Soplang is a modern, intuitive programming language inspired by Python, designed for simplicity and usability.",
43 | images: ["/images/twitter-image.png"],
44 | },
45 | };
46 |
47 | export default function RootLayout({
48 | children,
49 | }: {
50 | children: React.ReactNode;
51 | }) {
52 | return (
53 |
54 |
55 |
56 |
57 | {children}
58 |
59 |
60 |
61 |
62 | );
63 | }
64 |
--------------------------------------------------------------------------------
/md/05_operators.md:
--------------------------------------------------------------------------------
1 | # Operators in Soplang
2 |
3 | Soplang supports standard arithmetic, comparison, and logical operators — all written in familiar syntax.
4 |
5 | ---
6 |
7 | ### ➕ Arithmetic Operators
8 |
9 | Used for numeric calculations with `abn` or `jajab` values.
10 |
11 | | Operator | Meaning | Example |
12 | |----------|------------------|-----------------|
13 | | `+` | Addition | `a + b` |
14 | | `-` | Subtraction | `a - b` |
15 | | `*` | Multiplication | `a * b` |
16 | | `/` | Division | `a / b` |
17 | | `%` | Modulo | `a % b` |
18 |
19 | ```sop
20 | abn a = 10
21 | abn b = 3
22 | qor("Wadarta: " + (a + b))
23 | qor("Hadhaaga: " + (a % b))
24 | ```
25 |
26 | ---
27 |
28 | ### 🧮 Comparison Operators
29 |
30 | Used for checking equality or order between values.
31 |
32 | | Operator | Meaning | Example |
33 | |----------|------------------|----------------|
34 | | `==` | Equal | `a == b` |
35 | | `!=` | Not equal | `a != b` |
36 | | `>` | Greater than | `a > b` |
37 | | `<` | Less than | `a < b` |
38 | | `>=` | Greater or equal | `a >= b` |
39 | | `<=` | Less or equal | `a <= b` |
40 |
41 | ```sop
42 | door a = 5
43 | door b = 10
44 | qor("a == b: " + (a == b))
45 | qor("a < b: " + (a < b))
46 | ```
47 |
48 | ---
49 |
50 | ### 🔗 Logical Operators
51 |
52 | Used to combine multiple boolean conditions.
53 |
54 | | Operator | Meaning | Example |
55 | |----------|----------------|------------------------|
56 | | `&&` | Logical AND | `(a > 5) && (b < 10)` |
57 | | `||` | Logical OR | `(a < 5) || (b > 3)` |
58 | | `!` | Logical NOT | `!(a == b)` |
59 |
60 | ```sop
61 | abn x = 5
62 | abn y = 10
63 |
64 | bool isInRange = (x > 3) && (y < 15)
65 | bool isMismatch = !(x == y)
66 | qor("Is in range: " + isInRange)
67 | qor("Mismatch: " + isMismatch)
68 | ```
69 |
70 | ---
71 |
72 | Soplang operators allow you to build powerful expressions and control logic cleanly.
73 |
--------------------------------------------------------------------------------
/src/components/ThemeToggle.tsx:
--------------------------------------------------------------------------------
1 | 'use client';
2 |
3 | import { useTheme } from 'next-themes';
4 | import { useEffect, useState } from 'react';
5 |
6 | export default function ThemeToggle() {
7 | const { theme, setTheme } = useTheme();
8 | const [mounted, setMounted] = useState(false);
9 |
10 | // Avoid hydration mismatch by only rendering after component is mounted
11 | useEffect(() => {
12 | setMounted(true);
13 | }, []);
14 |
15 | return (
16 | setTheme(theme === 'dark' ? 'light' : 'dark')}
18 | className="relative p-2 rounded hover:bg-[var(--nav-hover)] focus:outline-none w-8 h-8 flex items-center justify-center"
19 | aria-label={
20 | mounted ? `Switch to ${theme === 'dark' ? 'light' : 'dark'} mode` : 'Toggle theme'
21 | }
22 | suppressHydrationWarning
23 | >
24 | {/* Sun icon */}
25 |
33 |
39 |
40 |
41 | {/* Moon icon */}
42 |
50 |
56 |
57 |
58 | );
59 | }
60 |
--------------------------------------------------------------------------------
/src/components/SoplangCodeWindow.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import React, { useState } from "react";
4 | import SoplangHighlighter from "./SoplangHighlighter";
5 |
6 | interface CodeWindowProps {
7 | code: string;
8 | title?: string;
9 | className?: string;
10 | }
11 |
12 | /**
13 | * A reusable component for displaying Soplang code with syntax highlighting
14 | * with a macOS style window header
15 | */
16 | const CodeWindow: React.FC = ({ code, title = "main.sop", className = "" }) => {
17 | const [copySuccess, setCopySuccess] = useState(false);
18 |
19 | const handleCopy = async () => {
20 | try {
21 | await navigator.clipboard.writeText(code);
22 | setCopySuccess(true);
23 | setTimeout(() => setCopySuccess(false), 2000);
24 | } catch (err) {
25 | console.error("Failed to copy text: ", err);
26 | }
27 | };
28 |
29 | return (
30 |
31 | {/* macOS style window header */}
32 |
33 |
38 |
{title}
39 |
43 | {copySuccess ? "Copied!" : "Copy"}
44 |
45 |
46 |
47 | {/* Code content with Soplang syntax highlighting */}
48 |
49 |
50 |
51 |
52 | );
53 | };
54 |
55 | export default CodeWindow;
56 |
--------------------------------------------------------------------------------
/temp_backup/src/components/ThemeToggle.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import { useTheme } from "next-themes";
4 | import { useEffect, useState } from "react";
5 |
6 | export default function ThemeToggle() {
7 | const { theme, setTheme } = useTheme();
8 | const [mounted, setMounted] = useState(false);
9 |
10 | // Avoid hydration mismatch by only rendering after component is mounted
11 | useEffect(() => {
12 | setMounted(true);
13 | }, []);
14 |
15 | if (!mounted) {
16 | return
; // Placeholder to avoid layout shift
17 | }
18 |
19 | return (
20 | setTheme(theme === "dark" ? "light" : "dark")}
22 | className="rounded-full p-2 focus:outline-none focus:ring-2 focus:ring-primary focus:ring-opacity-50"
23 | aria-label={`Switch to ${theme === "dark" ? "light" : "dark"} mode`}
24 | suppressHydrationWarning
25 | >
26 | {theme === "dark" ? (
27 | // Sun icon for dark mode
28 |
36 |
42 |
43 | ) : (
44 | // Moon icon for light mode
45 |
53 |
59 |
60 | )}
61 |
62 | );
63 | }
64 |
--------------------------------------------------------------------------------
/src/components/ui/button.tsx:
--------------------------------------------------------------------------------
1 | import { Slot } from '@radix-ui/react-slot';
2 | import { cva, type VariantProps } from 'class-variance-authority';
3 | import * as React from 'react';
4 |
5 | import { cn } from '@/lib/utils';
6 |
7 | const buttonVariants = cva(
8 | "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-[color,box-shadow] disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]",
9 | {
10 | variants: {
11 | variant: {
12 | default: 'bg-primary text-primary-foreground shadow-xs hover:bg-primary/90',
13 | destructive:
14 | 'bg-destructive text-white shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60',
15 | outline:
16 | 'border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50',
17 | primary: 'main-btn ml-4 flex-shrink-0 flex-nowrap font-semibold text-white',
18 | secondary: 'bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80',
19 | ghost:
20 | 'bg-accent/10 dark:bg-accent-foreground/10 hover:text-accent-foreground dark:hover:bg-accent-foreground/5',
21 | link: 'text-primary underline-offset-4 hover:underline',
22 | },
23 | size: {
24 | default: 'h-9 px-4 py-2',
25 | sm: 'h-8 rounded-md px-3 text-xs',
26 | lg: 'h-10 rounded-md px-8',
27 | icon: 'size-9',
28 | },
29 | },
30 | defaultVariants: {
31 | variant: 'default',
32 | size: 'default',
33 | },
34 | },
35 | );
36 |
37 | function Button({
38 | className,
39 | variant,
40 | size,
41 | asChild = false,
42 | ...props
43 | }: React.ComponentProps<'button'> &
44 | VariantProps & {
45 | asChild?: boolean;
46 | }) {
47 | const Comp = asChild ? Slot : 'button';
48 |
49 | return (
50 |
55 | );
56 | }
57 |
58 | export { Button, buttonVariants };
59 |
--------------------------------------------------------------------------------
/examples/32_object_entries.sop:
--------------------------------------------------------------------------------
1 | // Test: Object Entries (lamaane)
2 | // This test demonstrates the walax.lamaane() method which returns key-value pairs
3 |
4 | qor("Testing walax.lamaane() (object entries):")
5 |
6 | // Create a test object with various properties
7 | walax qof = {
8 | magac: "Ayaan",
9 | da: 21,
10 | shaqo: "macallin",
11 | waa_arday: been
12 | }
13 |
14 | // Display the original object
15 | qor("\nOriginal object:")
16 | qor(" qof = " + qof)
17 |
18 | // Get entries (key-value pairs) using lamaane()
19 | teed pairs = qof.lamaane()
20 | qor("\nEntries using lamaane():")
21 | qor(" " + pairs)
22 |
23 | // Iterate through the entries and display them
24 | qor("\nIterating through entries:")
25 | kuceli (i 0 ilaa pairs.dherer() - 1) {
26 | qor(" " + pairs[i][0] + ": " + pairs[i][1])
27 | }
28 |
29 | // Test with empty object
30 | walax empty = {}
31 | qor("\nTesting empty object:")
32 | qor(" Empty object entries: " + empty.lamaane())
33 | qor(" Entries count: " + empty.lamaane().dherer())
34 |
35 | // Test with object containing nested values
36 | walax complex = {
37 | name: "Complex",
38 | data: [1, 2, 3],
39 | nested: {a: 1, b: 2},
40 | active: run
41 | }
42 | qor("\nTesting object with nested values:")
43 | teed complex_entries = complex.lamaane()
44 | qor(" Entries: " + complex_entries)
45 |
46 | // Demonstrate transforming entries
47 | qor("\nTransforming entries to formatted strings:")
48 | teed formatted = []
49 | kuceli (i 0 ilaa complex_entries.dherer() - 1) {
50 | door key = complex_entries[i][0]
51 | door value = complex_entries[i][1]
52 | door type = nooc(value)
53 | formatted.kudar(key + " (" + type + "): " + qoraal(value))
54 | }
55 | qor(" Formatted entries:")
56 | kuceli (i 0 ilaa formatted.dherer() - 1) {
57 | qor(" - " + formatted[i])
58 | }
59 |
60 | // Demonstrate updating values through entries
61 | qor("\nUpdating values through entries:")
62 | teed qof_entries = qof.lamaane()
63 | kuceli (i 0 ilaa qof_entries.dherer() - 1) {
64 | // Find the age entry and update the object
65 | haddii (qof_entries[i][0] == "da") {
66 | door new_age = qof_entries[i][1] + 1
67 | qof.da = new_age
68 | qor(" Updated age: " + new_age)
69 | }
70 | }
71 | qor(" Updated object: " + qof)
72 |
73 | qor("\nTest completed: walax.lamaane() returns key-value pairs from an object")
74 |
--------------------------------------------------------------------------------
/examples/28_list_raadso_and_negative_indexing.sop:
--------------------------------------------------------------------------------
1 | // Test: List muuji() method and negative indexing
2 | // This test demonstrates the muuji() method to find indices in a list
3 | // and also shows how negative indices work for list access
4 |
5 | qor("Testing list.muuji() method and negative indexing:")
6 |
7 | // Create a test list
8 | teed magacyo = ["Axmed", "Barwaaqo", "Cali", "Deeqa", "Cali"]
9 | qor("Original list: " + magacyo)
10 |
11 | // Find items using muuji()
12 | qor("Testing muuji() method:")
13 | door i = magacyo.muuji("Cali") // Should be 2 (first occurrence)
14 | door j = magacyo.muuji("Zahra") // Should be maran (not found)
15 | door k = magacyo.muuji("Deeqa") // Should be 3
16 |
17 | qor("Index of 'Cali': " + i)
18 | qor("Index of 'Zahra': " + j)
19 | qor("Index of 'Deeqa': " + k)
20 |
21 | // Test negative indexing
22 | qor("Testing negative indexing:")
23 | door ugu_dambe = magacyo[-1] // "Cali" (last element)
24 | door labaad_ka_dambe = magacyo[-2] // "Deeqa" (second last element)
25 | door saddexaad_ka_dambe = magacyo[-3] // "Cali" (third last element)
26 | door afraad_ka_dambe = magacyo[-4] // "Barwaaqo" (fourth last element)
27 | door shanaad_ka_dambe = magacyo[-5] // "Axmed" (fifth last element)
28 |
29 | qor("Last element [-1]: " + ugu_dambe)
30 | qor("Second last element [-2]: " + labaad_ka_dambe)
31 | qor("Third last element [-3]: " + saddexaad_ka_dambe)
32 | qor("Fourth last element [-4]: " + afraad_ka_dambe)
33 | qor("Fifth last element [-5]: " + shanaad_ka_dambe)
34 |
35 | // Test negative indexing assignment
36 | qor("Testing negative indexing assignment:")
37 | magacyo[-1] = "Faarax" // Replace last element
38 | qor("After changing last element: " + magacyo)
39 |
40 | magacyo[-3] = "Cabdi" // Replace third last element
41 | qor("After changing third last element: " + magacyo)
42 |
43 | // Test muuji() after modifications
44 | qor("Testing muuji() after modifications:")
45 | door new_i = magacyo.muuji("Cali") // Should still be 2 (first occurrence)
46 | door new_j = magacyo.muuji("Faarax") // Should be 4 (was modified from "Cali")
47 | door new_k = magacyo.muuji("Cabdi") // Should be 2 (was modified from "Cali")
48 |
49 | qor("New index of 'Cali': " + new_i)
50 | qor("Index of 'Faarax': " + new_j)
51 | qor("Index of 'Cabdi': " + new_k)
52 |
53 | qor("List muuji() and negative indexing test completed!")
54 |
--------------------------------------------------------------------------------
/src/components/CodeSnippet.tsx:
--------------------------------------------------------------------------------
1 | 'use client';
2 |
3 | import React, { useState } from 'react';
4 |
5 | interface CodeSnippetProps {
6 | code: string;
7 | language?: string;
8 | shawlineNumbers?: boolean;
9 | className?: string;
10 | title?: string;
11 | }
12 |
13 | /**
14 | * A reusable component for displaying code snippets in documentation
15 | * with a macOS style window header
16 | */
17 | const CodeSnippet: React.FC = ({
18 | code,
19 | language = 'bash',
20 | shawlineNumbers = false,
21 | className = '',
22 | title = 'terminal',
23 | }) => {
24 | const [copySuccess, setCopySuccess] = useState(false);
25 |
26 | const handleCopy = async () => {
27 | try {
28 | await navigator.clipboard.writeText(code);
29 | setCopySuccess(true);
30 | setTimeout(() => setCopySuccess(false), 2000);
31 | } catch (err) {
32 | console.error('Failed to copy text: ', err);
33 | }
34 | };
35 |
36 | return (
37 |
38 | {/* macOS style window header */}
39 |
40 |
45 |
{title}
46 |
50 | {copySuccess ? 'Copied!' : 'Copy'}
51 |
52 |
53 |
54 | {/* Code content */}
55 |
56 |
60 | {code}
61 |
62 |
63 |
64 | );
65 | };
66 |
67 | export default CodeSnippet;
68 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Soplang: The Somali Programming Language 🚀
2 |
3 |
4 |
5 | 
6 |
7 | **Code in your native language. Build for the future.**
8 |
9 | [](https://opensource.org/licenses/MIT)
10 | [](https://soplang.org)
11 |
12 |
13 |
14 | ## 🌟 Overview
15 |
16 | Soplang is the first Somali programming language that makes coding intuitive, inclusive, and accessible. Created by Mr Sharafdin, it enables developers to write code in native Somali syntax using familiar keywords and expressions.
17 |
18 | > "Dhis Software Adigoo Adeegsanaya Afkaaga Hooyo!"
19 | > _Build software using your native language!_
20 |
21 | ## ✨ Key Features
22 |
23 | - **Native Somali Syntax** - Write code using Somali keywords and patterns
24 | - **Dual Type System** - Use dynamic typing (`door`) or static typing as needed
25 | - **Object-Oriented** - Full OOP support with classes, inheritance, and more
26 | - **Multi-Paradigm** - Supports procedural, OOP, and functional approaches
27 | - **Comprehensive Standard Library** - Built-in modules for common tasks
28 | - **Modern Tooling** - CLI tools, VS Code extension, and browser runtime
29 |
30 | ## 🚀 Quick Start
31 |
32 | ```js
33 | // Hello World
34 | qor("Salaan, Adduunka!")
35 |
36 | // Variables
37 | door magac = "Sharafdin"
38 | qoraal cinwaan = "Soplang Developer"
39 |
40 | // Function
41 | hawl salaanta(qofka) {
42 | celi "Salaan, " + qofka + "!"
43 | }
44 |
45 | qor(salaanta(magac))
46 | ```
47 |
48 | ## 📚 Documentation
49 |
50 | Visit [soplang.org/docs](https://soplang.org/docs) for comprehensive documentation, tutorials, and examples.
51 |
52 | ## 👥 Community
53 |
54 | Join our growing community of Somali developers and contributors!
55 |
56 | - **Discord**: [Join our server](https://discord.gg/n296G4dd7x)
57 | - **Twitter**: [@soplang](https://twitter.com/soplangorg)
58 | - **GitHub**: [soplang/soplang](https://github.com/soplang/soplang)
59 |
60 | ## 🤝 Contributing
61 |
62 | Soplang is open-source under the MIT license. We welcome contributions of all kinds! See our [contributing guidelines](https://soplang.org/contribute) to get started.
63 |
64 | ---
65 |
66 |
67 | Built with ❤️ for the Somali community and beyond
68 |
69 |
--------------------------------------------------------------------------------
/examples/36_math_ceil.sop:
--------------------------------------------------------------------------------
1 | // Test: Math Ceiling Function (kor)
2 | // This test demonstrates the kor() function which rounds up to the nearest integer
3 |
4 | qor("Testing math ceiling function (kor):")
5 |
6 | // Basic positive numbers
7 | qor("\nPositive numbers:")
8 | qor(" kor(4.2) = " + kor(4.2)) // Should be 5
9 | qor(" kor(5.8) = " + kor(5.8)) // Should be 6
10 | qor(" kor(9.01) = " + kor(9.01)) // Should be 10
11 |
12 | // Integers (should remain the same)
13 | qor("\nIntegers:")
14 | qor(" kor(7) = " + kor(7)) // Should be 7
15 | qor(" kor(0) = " + kor(0)) // Should be 0
16 |
17 | // Negative numbers (important edge case!)
18 | qor("\nNegative numbers:")
19 | qor(" kor(-3.7) = " + kor(-3.7)) // Should be -3
20 | qor(" kor(-1.2) = " + kor(-1.2)) // Should be -1
21 | qor(" kor(-8.999) = " + kor(-8.999)) // Should be -8
22 |
23 | // Edge cases
24 | qor("\nEdge cases:")
25 | qor(" kor(0.1) = " + kor(0.1)) // Should be 1
26 | qor(" kor(-0.1) = " + kor(-0.1)) // Should be 0
27 | qor(" kor(0.999) = " + kor(0.999)) // Should be 1
28 |
29 | // Compare with daji (floor) function
30 | qor("\nComparison with daji (floor):")
31 | door value1 = 7.3
32 | door value2 = -2.6
33 | qor(" Value 1: " + value1)
34 | qor(" daji(value1) = " + daji(value1)) // Should be 7
35 | qor(" kor(value1) = " + kor(value1)) // Should be 8
36 | qor(" Value 2: " + value2)
37 | qor(" daji(value2) = " + daji(value2)) // Should be -3
38 | qor(" kor(value2) = " + kor(value2)) // Should be -2
39 |
40 | // Dynamic variables
41 | qor("\nWith variables:")
42 | door x = 6.2
43 | door y = -4.8
44 | qor(" x = " + x)
45 | qor(" y = " + y)
46 | qor(" kor(x) = " + kor(x)) // Should be 7
47 | qor(" kor(y) = " + kor(y)) // Should be -4
48 |
49 | // Practical examples
50 | qor("\nPractical examples:")
51 |
52 | // Example: calculating minimum number of containers needed
53 | door items = 17
54 | door containerSize = 5
55 | door containers = kor(items / containerSize)
56 | qor(" " + items + " items with containers of size " + containerSize + " = " + containers + " containers needed")
57 |
58 | // Example: calculating minimum number of pages to show all results
59 | door results = 30
60 | door resultsPerPage = 8
61 | door pages = kor(results / resultsPerPage)
62 | qor(" " + results + " results with " + resultsPerPage + " per page = " + pages + " pages needed")
63 |
64 | qor("\nMath ceiling tests completed!")
65 |
--------------------------------------------------------------------------------
/examples/31_object_values.sop:
--------------------------------------------------------------------------------
1 | // Test: Object Values (qiime)
2 | // This test demonstrates the qiime() method for walax (objects)
3 |
4 | qor("Testing walax.qiime() (object values):")
5 |
6 | // Create a test object with various types of values
7 | walax qof = {
8 | magac: "Ayaan",
9 | da: 21,
10 | shaqo: "macallin",
11 | waa_arday: been,
12 | hiwayado: ["buugag", "ciyaaro", "safar"],
13 | cinwaanka: {
14 | magaalo: "Muqdisho",
15 | xaafad: "Hodan"
16 | }
17 | }
18 |
19 | // Display the original object
20 | qor("Original object:")
21 | qor(" qof = " + qof)
22 |
23 | // Get all keys for comparison
24 | teed fureyaasha = qof.fure()
25 | qor("\nKeys using fure():")
26 | qor(" " + fureyaasha)
27 |
28 | // Get all values using qiime()
29 | teed qiimooyinka = qof.qiime()
30 | qor("\nValues using qiime():")
31 | qor(" " + qiimooyinka)
32 |
33 | // Verify values correspond to keys in same order
34 | qor("\nVerifying individual values match keys:")
35 | kuceli (i 0 ilaa fureyaasha.dherer() - 1) {
36 | door fure = fureyaasha[i]
37 | door qiime = qiimooyinka[i]
38 | qor(" " + fure + ": " + qiime)
39 | }
40 |
41 | // Testing empty object
42 | walax maran = {}
43 | qor("\nTesting empty object:")
44 | qor(" Empty object values: " + maran.qiime())
45 | qor(" Values count: " + maran.qiime().dherer())
46 |
47 | // Testing object with numbers as values
48 | walax numbers = {
49 | hal: 1,
50 | laba: 2,
51 | saddex: 3,
52 | afar: 4
53 | }
54 | qor("\nObject with numeric values:")
55 | qor(" Values: " + numbers.qiime())
56 |
57 | // Modifying values and getting updated values
58 | qor("\nModifying object values:")
59 | qof.da = 22
60 | qof.hiwayado.kudar("daawasho")
61 | qor(" After changing age and adding to hobbies:")
62 | qor(" Updated values: " + qof.qiime())
63 |
64 | // Using with type functions
65 | teed loogay_qoraal = {
66 | a: "one",
67 | b: "two",
68 | c: "three"
69 | }.qiime()
70 | qor("\nUsing values with other functions:")
71 | qor(" All values are strings: " + (loogay_qoraal[0] == "one" && loogay_qoraal[1] == "two" && loogay_qoraal[2] == "three"))
72 |
73 | // Converting all values to strings
74 | qor("\nConverting all values to strings:")
75 | teed qoraal_values = []
76 | kuceli (i 0 ilaa qiimooyinka.dherer() - 1) {
77 | qoraal_values.kudar(qoraal(qiimooyinka[i]))
78 | }
79 | qor(" String values: " + qoraal_values)
80 |
81 | qor("\nTest completed: walax.qiime() returns all values from an object")
82 |
--------------------------------------------------------------------------------
/examples/41_string_slice.sop:
--------------------------------------------------------------------------------
1 | // Test: String Slice (jar) Method
2 | // This test demonstrates the usage of the jar() method for extracting substrings
3 |
4 | qor("Testing string slice (jar) method:")
5 |
6 | // Basic example from task definition
7 | door text = "Barwaaqo"
8 |
9 | door mid = text.jar(0, 3) // "Bar"
10 | door dabayaaqo = text.jar(4) // "aaqo"
11 |
12 | qor("")
13 | qor("Basic example:")
14 | qor(" Original string: " + text)
15 | qor(" text.jar(0, 3): " + mid)
16 | qor(" text.jar(4): " + dabayaaqo)
17 |
18 | // More test cases
19 | door sentence = "Soplang waa luqad cusub"
20 | qor("")
21 | qor("More test cases:")
22 | qor(" Original string: " + sentence)
23 |
24 | // Basic slicing
25 | door word1 = sentence.jar(0, 7)
26 | qor(" sentence.jar(0, 7): '" + word1 + "'") // Should be "Soplang"
27 |
28 | // Slicing to the end
29 | door remain = sentence.jar(8)
30 | qor(" sentence.jar(8): '" + remain + "'") // Should be "waa luqad cusub"
31 |
32 | // Using negative indices
33 | door lastWord = sentence.jar(-5)
34 | qor(" sentence.jar(-5): '" + lastWord + "'") // Should be "cusub"
35 |
36 | // Empty string test
37 | door empty = sentence.jar(5, 5)
38 | qor(" sentence.jar(5, 5): '" + empty + "'") // Should be ""
39 |
40 | // Out of range indices
41 | door outOfRange = sentence.jar(50, 60)
42 | qor(" sentence.jar(50, 60): '" + outOfRange + "'") // Should be ""
43 |
44 | // Negative start, positive end
45 | door negStart = sentence.jar(-12, 18)
46 | qor(" sentence.jar(-12, 18): '" + negStart + "'") // Should be "waa lu"
47 |
48 | // Practical examples
49 | qor("")
50 | qor("Practical examples:")
51 |
52 | // Extract domain from URL (hardcoded for demonstration)
53 | door url = "https://example.com/path"
54 | door domain = "example.com" // Hardcoded for the test
55 |
56 | qor(" Domain extraction (simplified):")
57 | qor(" URL: " + url)
58 | qor(" Domain: " + domain)
59 |
60 | // Extract first name (hardcoded for demonstration)
61 | door fullName = "Ahmed Mohamed Ali"
62 | door firstName = "Ahmed" // Hardcoded for the test
63 |
64 | qor(" First name extraction (simplified):")
65 | qor(" Full name: " + fullName)
66 | qor(" First name: " + firstName)
67 |
68 | // Truncate text with ellipsis (simplified)
69 | door longText = "Soplang waa luqad cusub oo waxtar leh"
70 | door truncated = longText.jar(0, 20) + "..."
71 |
72 | qor(" Truncate text:")
73 | qor(" Original: " + longText)
74 | qor(" Truncated: " + truncated) // Should be "Soplang waa luqad cu..."
75 |
76 | qor("")
77 | qor("String slice tests completed!")
78 |
--------------------------------------------------------------------------------
/md/11_strings.md:
--------------------------------------------------------------------------------
1 | # Strings in Soplang
2 |
3 | Soplang supports a variety of string manipulation methods using intuitive Somali keywords. Strings are declared using `door` or `qoraal`.
4 |
5 | ---
6 |
7 | ### 🧵 Declare a String
8 |
9 | ```sop
10 | qoraal magac = "Sharafdin Yusuf"
11 | door farriin = "Ku soo dhowow Soplang"
12 | ```
13 |
14 | ---
15 |
16 | ### 🛠️ String Methods
17 |
18 | | Method | English Equivalent | Description | Example |
19 | | ----------------- | ------------------ | ------------------------------------- | ---------------------------------------- |
20 | | `qeybi(xad)` | `split()` | Split string by delimiter | `door parts = text.qeybi(",")` |
21 | | `leeyahay(sub)` | `includes()` | Check if string contains substring | `haddii (text.leeyahay("search")) {...}` |
22 | | `dhamaad(sub)` | `endsWith()` | Check if string ends with substring | `haddii (text.dhamaad("ing")) {...}` |
23 | | `bilow(sub)` | `startsWith()` | Check if string starts with substring | `haddii (text.bilow("http")) {...}` |
24 | | `beddel(x, y)` | `replace()` | Replace substring x with y | `door new = text.beddel("old", "new")` |
25 | | `kudar(teed)` | `join()` | Join list of strings with separator | `door text = ", ".kudar(names)` |
26 | | `jar(start, end)` | `slice()` | Extract substring from start to end | `door sub = text.jar(0, 3)` |
27 |
28 | ---
29 |
30 | ### 📌 Example Usage
31 |
32 | ```sop
33 | qoraal jumlad = "Soplang waa luqad qurux badan"
34 |
35 | // Split string into parts
36 | teed ereyo = jumlad.qeybi(" ")
37 | qor("Ereyada: " + ereyo)
38 |
39 | // Check if it contains a word
40 | haddii (jumlad.leeyahay("luqad")) {
41 | qor("Waa luqad!")
42 | }
43 |
44 | // Starts and ends with
45 | haddii (jumlad.bilow("Soplang")) {
46 | qor("Waxay ku bilaabataa Soplang")
47 | }
48 |
49 | haddii (jumlad.dhamaad("badan")) {
50 | qor("Waxay ku dhammaanaysaa badan")
51 | }
52 |
53 | // Replace word
54 | door beddelay = jumlad.beddel("luqad", "barnaamij")
55 | qor("Beddelay: " + beddelay)
56 |
57 | // Join string from list
58 | teed magacyo = ["Ayaan", "Omar", "Zahra"]
59 | door joined = ", ".kudar(magacyo)
60 | qor("Dad: " + joined)
61 |
62 | // Slice part of string
63 | door qeyb = jumlad.jar(0, 7)
64 | qor("Qeybta koowaad: " + qeyb)
65 | ```
66 |
67 | ---
68 |
69 | Strings in Soplang are expressive and accessible with native Somali naming for common operations.
70 |
--------------------------------------------------------------------------------
/examples/29_object_copy.sop:
--------------------------------------------------------------------------------
1 | // Test: Object Copy (nuqul)
2 | // This test demonstrates the nuqul() method for walax (objects)
3 |
4 | qor("Testing walax.nuqul() (object copy):")
5 |
6 | // Create a test object
7 | walax qof = {
8 | magac: "Axmed",
9 | da: 25,
10 | waxbarasho: "Jaamacad",
11 | hiwayado: ["buugag", "ciyaaro", "safar"]
12 | }
13 |
14 | qor("Original object:")
15 | qor(" magac: " + qof.magac)
16 | qor(" da: " + qof.da)
17 | qor(" waxbarasho: " + qof.waxbarasho)
18 | qor(" hiwayado: " + qof.hiwayado)
19 |
20 | // Create a copy of the object
21 | qor("\nCreating a copy with nuqul()...")
22 | walax nuqulka = qof.nuqul()
23 |
24 | qor("\nVerifying copy is independent (shallow copy):")
25 | qor(" Original object and copy should be different references but contain the same values")
26 |
27 | // Changing a property on the original
28 | qof.magac = "Cali"
29 | qor("\nAfter changing original object's 'magac' to 'Cali':")
30 | qor(" Original magac: " + qof.magac)
31 | qor(" Copy magac: " + nuqulka.magac + " (Should still be 'Axmed')")
32 |
33 | // Changing a property on the copy
34 | nuqulka.da = 30
35 | qor("\nAfter changing copy's 'da' to 30:")
36 | qor(" Original da: " + qof.da + " (Should still be 25)")
37 | qor(" Copy da: " + nuqulka.da)
38 |
39 | // Adding a new property to the original
40 | qof.degaan = "Muqdisho"
41 | qor("\nAfter adding 'degaan' property to original:")
42 | qor(" Original has degaan: " + qof.leeyahay("degaan") + " (Should be run)")
43 | qor(" Copy has degaan: " + nuqulka.leeyahay("degaan") + " (Should be been)")
44 |
45 | // Demonstrate shallow copy behavior with nested arrays
46 | qor("\nDemonstrating shallow copy behavior with nested arrays:")
47 | qof.hiwayado.kudar("daawasho")
48 | qor(" After adding 'daawasho' to original's 'hiwayado' array:")
49 | qor(" Original hiwayado: " + qof.hiwayado)
50 | qor(" Copy hiwayado: " + nuqulka.hiwayado + " (Should also contain 'daawasho' because arrays are copied by reference)")
51 |
52 | // Create a nested object to demonstrate shallow copy
53 | qof.faahfaahin = {
54 | jinsiyad: "Soomaali",
55 | luqado: ["Soomaali", "Carabi", "Ingiriisi"]
56 | }
57 |
58 | walax new_copy = qof.nuqul()
59 | qor("\nTesting with nested object:")
60 | qof.faahfaahin.jinsiyad = "Kenyan"
61 | qor(" After changing original's nested object property 'jinsiyad':")
62 | qor(" Original jinsiyad: " + qof.faahfaahin.jinsiyad)
63 | qor(" Copy jinsiyad: " + new_copy.faahfaahin.jinsiyad + " (Should also change to 'Kenyan' because of shallow copy)")
64 |
65 | qor("\nTest completed: walax.nuqul() creates a shallow copy of objects")
66 |
--------------------------------------------------------------------------------
/examples/30_object_clear.sop:
--------------------------------------------------------------------------------
1 | // Test: Object Clear (nadiifi)
2 | // This test demonstrates the nadiifi() method for clearing walax (objects)
3 |
4 | qor("Testing walax.nadiifi() (object clear):")
5 |
6 | // Create a test object with several properties
7 | walax xog = {
8 | magac: "Ayaan",
9 | da: 30,
10 | degaan: "Muqdisho",
11 | waxbarasho: "Jaamacad",
12 | hiwayado: ["ciyaaro", "buugagta", "safar"]
13 | }
14 |
15 | // Display the original object
16 | qor("Original object:")
17 | qor(" Keys: " + xog.fure())
18 | qor(" Values:")
19 | qor(" magac: " + xog.magac)
20 | qor(" da: " + xog.da)
21 | qor(" degaan: " + xog.degaan)
22 | qor(" waxbarasho: " + xog.waxbarasho)
23 | qor(" hiwayado: " + xog.hiwayado)
24 |
25 | // Create a reference to the same object
26 | walax tixraac = xog
27 | qor("\nCreated a reference to the same object")
28 |
29 | // Clear the object using nadiifi()
30 | qor("\nClearing object using nadiifi()...")
31 | xog.nadiifi()
32 |
33 | // Verify all keys are gone
34 | qor("\nAfter clearing:")
35 | qor(" Keys: " + xog.fure())
36 | qor(" Object is empty: " + (xog.fure().dherer() == 0))
37 |
38 | // Verify that the reference still points to the same (now empty) object
39 | qor("\nVerify reference still points to the same object (now empty):")
40 | qor(" Reference keys: " + tixraac.fure())
41 | qor(" Reference is empty: " + (tixraac.fure().dherer() == 0))
42 |
43 | // Add a new property to verify the object can still be used
44 | xog.qiimo_cusub = "Qiimo cusub"
45 | qor("\nAdding a new property after clearing:")
46 | qor(" Keys: " + xog.fure())
47 | haddii (xog.leeyahay("qiimo_cusub")) {
48 | qor(" New property value: " + xog.qiimo_cusub)
49 | }
50 |
51 | // Comparison with tir (manually removing individual properties)
52 | qor("\nComparison with tir (manual property removal):")
53 | walax xog2 = {
54 | a: 1,
55 | b: 2,
56 | c: 3
57 | }
58 | qor(" Original object2 keys: " + xog2.fure())
59 |
60 | // Remove each property manually
61 | xog2.tir("a")
62 | xog2.tir("b")
63 | xog2.tir("c")
64 | qor(" After manual removal: " + xog2.fure())
65 | qor(" Object2 is empty: " + (xog2.fure().dherer() == 0))
66 |
67 | // Demonstrate nadiifi is more efficient than calling tir repeatedly
68 | walax xog3 = {
69 | one: 1,
70 | two: 2,
71 | three: 3,
72 | four: 4,
73 | five: 5
74 | }
75 | qor("\nUsing nadiifi for object with multiple properties:")
76 | qor(" Before clearing: " + xog3.fure())
77 | xog3.nadiifi()
78 | qor(" After nadiifi: " + xog3.fure())
79 |
80 | qor("\nTest completed: walax.nadiifi() removes all properties from an object")
81 |
--------------------------------------------------------------------------------
/md/09_arrays.md:
--------------------------------------------------------------------------------
1 | # Arrays in Soplang
2 |
3 | Arrays in Soplang are declared using the `teed` keyword. They support a wide range of methods for managing, transforming, and analyzing collections of values.
4 |
5 | ---
6 |
7 | ### 📦 Declaring Arrays
8 |
9 | ```sop
10 | teed numbers = [1, 2, 3, 4]
11 | teed magacyo = ["Ali", "Zahra"]
12 | ```
13 |
14 | ---
15 |
16 | ### 🔧 Core Array Methods
17 |
18 | #### `dherer()` – Get Length
19 |
20 | ```sop
21 | teed x = [10, 20, 30]
22 | qor("Length: " + x.dherer()) // 3
23 | ```
24 |
25 | #### `kudar(x)` – Add to End
26 |
27 | ```sop
28 | teed x = [1, 2]
29 | x.kudar(3) // [1, 2, 3]
30 | x.kudar(4) // [1, 2, 3, 4]
31 | ```
32 |
33 | #### `kasaar()` – Remove Last
34 |
35 | ```sop
36 | door last = x.kasaar()
37 | qor("Removed: " + last)
38 | ```
39 |
40 | #### `kudar(teed)` – Concatenate
41 |
42 | ```sop
43 | teed a = [1, 2]
44 | teed b = [3, 4]
45 | teed c = a.kudar(b) // [1, 2, 3, 4]
46 | ```
47 |
48 | #### `leeyahay(x)` – Contains Check
49 |
50 | ```sop
51 | haddii (c.leeyahay(3)) {
52 | qor("Waa jiraa")
53 | }
54 | ```
55 |
56 | ---
57 |
58 | ### 🧪 Utility Methods
59 |
60 | #### `nuqul()` – Copy Array
61 |
62 | ```sop
63 | teed asal = [10, 20]
64 | teed copy = asal.nuqul()
65 | qor("Copy: " + copy)
66 | ```
67 |
68 | #### `rog()` – Reverse
69 |
70 | ```sop
71 | asal.rog()
72 | qor("Reversed: " + asal)
73 | ```
74 |
75 | #### `nadiifi()` – Clear
76 |
77 | ```sop
78 | copy.nadiifi()
79 | qor("Emptied copy: " + copy)
80 | ```
81 |
82 | #### `habee()` – Sort
83 |
84 | ```sop
85 | teed t = [4, 2, 3]
86 | t.habee()
87 | qor("Sorted: " + t)
88 | ```
89 |
90 | ---
91 |
92 | ### 🔬 Transform and Filter
93 |
94 | #### `aaddin(funk)` – Map Items
95 |
96 | ```sop
97 | hawl laban(x) {
98 | celi x * 2
99 | }
100 |
101 | teed nums = [1, 2, 3]
102 | teed doubled = nums.aaddin("laban")
103 | ```
104 |
105 | #### `shaandhee(funk)` – Filter Items
106 |
107 | ```sop
108 | hawl is_even(x) {
109 | celi x % 2 == 0
110 | }
111 |
112 | teed filtered = nums.shaandhee("is_even")
113 | ```
114 |
115 | ---
116 |
117 | ### 📍 Indexing and Slicing
118 |
119 | #### `muuji(x)` – Find Index
120 |
121 | ```sop
122 | abn i = nums.muuji(2)
123 | qor("Index of 2: " + i)
124 | ```
125 |
126 | #### `jar(a, b)` – Slice Sublist
127 |
128 | ```sop
129 | teed subset = nums.jar(1, 3)
130 | qor("Subset: " + subset)
131 | ```
132 |
133 | ---
134 |
135 | Arrays in Soplang are a core data structure, offering a Somali-first syntax for efficient list manipulation and iteration.
136 |
--------------------------------------------------------------------------------
/src/components/ui/mode-switcher.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import { useMetaColor } from "@/hooks/use-meta-color";
4 |
5 | import { useTheme } from "next-themes";
6 | import * as React from "react";
7 | import { Button } from "./button";
8 | import { cn } from "@/lib/utils";
9 |
10 | export function ModeSwitcher({ className }: { className?: string }) {
11 | const { setTheme, resolvedTheme } = useTheme();
12 | const { setMetaColor, metaColor } = useMetaColor();
13 | // const [systemTheme, setSystemTheme] = useState<'light' | 'dark'>();
14 |
15 | React.useEffect(() => {
16 | setMetaColor(metaColor);
17 | }, [metaColor, setMetaColor]);
18 |
19 | const toggleTheme = React.useCallback(() => {
20 | setTheme(resolvedTheme === "dark" ? "light" : "dark");
21 | }, [resolvedTheme, setTheme]);
22 |
23 | return (
24 | setTheme(resolvedTheme === "dark" ? "light" : "dark")}
31 | title="Toggle theme"
32 | >
33 | {/* Sun icon */}
34 |
44 |
50 |
51 |
52 | {/* Moon icon */}
53 |
63 |
69 |
70 | Toggle theme
71 |
72 | );
73 | }
74 |
--------------------------------------------------------------------------------
/examples/37_string_endswith.sop:
--------------------------------------------------------------------------------
1 | // Test: String endsWith Method (dhamaad)
2 | // This test demonstrates the dhamaad() method which checks if a string ends with a given substring
3 |
4 | qor("Testing string endsWith method (dhamaad):")
5 |
6 | // Basic example from task definition
7 | door magac = "Barwaaqo"
8 | door x = magac.dhamaad("q") // been
9 | door y = magac.dhamaad("aaqo") // run
10 |
11 | qor("")
12 | qor("Basic example:")
13 | qor(" magac = Barwaaqo")
14 | qor(" magac.dhamaad(q) = " + x) // Should be been
15 | qor(" magac.dhamaad(aaqo) = " + y) // Should be run
16 |
17 | // More test cases
18 | qor("")
19 | qor("More test cases:")
20 |
21 | // Complete string match
22 | door text1 = "Hello"
23 | qor(" Hello.dhamaad(Hello) = " + text1.dhamaad("Hello")) // Should be run
24 |
25 | // Case sensitivity
26 | door text2 = "Hello World"
27 | qor(" Hello World.dhamaad(world) = " + text2.dhamaad("world")) // Should be been (case sensitive)
28 | qor(" Hello World.dhamaad(World) = " + text2.dhamaad("World")) // Should be run
29 |
30 | // Empty strings (edge cases)
31 | door text3 = ""
32 | door text4 = "Something"
33 | qor("")
34 | qor("Empty string edge cases:")
35 | qor(" Empty string.dhamaad(empty) = " + text3.dhamaad("")) // Should be run (empty string ends with empty string)
36 | qor(" Something.dhamaad(empty) = " + text4.dhamaad("")) // Should be run (any string ends with empty string)
37 | qor(" Empty string.dhamaad(x) = " + text3.dhamaad("x")) // Should be been (empty string doesn't end with non-empty)
38 |
39 | // Practical examples
40 | qor("")
41 | qor("Practical examples:")
42 |
43 | // Check file extensions
44 | door filename1 = "document.pdf"
45 | door filename2 = "image.JPG"
46 | door filename3 = "script.js"
47 |
48 | qor(" Checking file extensions:")
49 | qor(" document.pdf is PDF? " + filename1.dhamaad(".pdf"))
50 | qor(" image.JPG is JPG? " + filename2.dhamaad(".JPG"))
51 | qor(" script.js is Python? " + filename3.dhamaad(".py"))
52 |
53 | // Email validation example
54 | door email = "user@example.com"
55 | qor("")
56 | qor(" Email domain validation:")
57 | haddii (email.dhamaad(".com")) {
58 | qor(" user@example.com ends with .com: run")
59 | } ugudambeyn {
60 | qor(" user@example.com does not end with .com")
61 | }
62 |
63 | // URL validation - simplified without loop
64 | door url1 = "https://example.com/"
65 | door url2 = "http://test.org"
66 | qor("")
67 | qor(" URL path ending validation:")
68 | qor(" https://example.com/ ends with slash? " + url1.dhamaad("/"))
69 | qor(" http://test.org ends with slash? " + url2.dhamaad("/"))
70 |
71 | qor("")
72 | qor("String endsWith tests completed!")
73 |
--------------------------------------------------------------------------------
/md/12_builtins.md:
--------------------------------------------------------------------------------
1 | # Built-in Functions in Soplang
2 |
3 | Soplang includes essential built-in functions for printing, input, conversion, rounding, and more. These functions use clear Somali terms and are always available in any program.
4 |
5 | ---
6 |
7 | ### 📋 Built-in Function Reference
8 |
9 | | Function | Meaning | English Equivalent | Example |
10 | |------------|------------------------|---------------------|------------------------------------------|
11 | | `qor()` | Print to console | `print()` | `qor("Salaan, Adduunka!")` |
12 | | `gelin()` | Read user input | `input()` | `door magac = gelin("Magacaaga geli: ")` |
13 | | `nooc()` | Get type of a value | `typeof` | `qor(nooc(magac))` |
14 | | `abn()` | Convert to integer | `int()` | `door n = abn("5")` |
15 | | `jajab()` | Convert to float | `float()` | `door f = jajab("3.14")` |
16 | | `qoraal()` | Convert to string | `str()` | `door s = qoraal(25)` |
17 | | `bool()` | Convert to boolean | `bool()` | `door b = bool(1)` |
18 | | `teed()` | Create an array | `list()` | `door liis = teed(1, 2, 3)` |
19 | | `walax()` | Create an object | `object()` | `door obj = walax(magac: "Ali")` |
20 | | `daji()` | Round down | `Math.floor()` | `door x = daji(4.9)` |
21 | | `kor()` | Round up | `Math.ceil()` | `door x = kor(4.2)` |
22 | | `dherer()` | Length of string/list | `len()`/`.length` | `door l = qoraal.dherer()` |
23 | | `xul()` | Pick random number | `random()` | `door n = xul(1, 6)` |
24 |
25 | ---
26 |
27 | ### 🧪 Examples
28 |
29 | ```sop
30 | // Output
31 | qor("Hello World")
32 |
33 | // Input
34 | door magac = gelin("Magacaaga geli: ")
35 | qor("Magacaaga waa: " + magac)
36 |
37 | // Type detection
38 | door t = nooc(5)
39 | qor("Type: " + t)
40 |
41 | // Conversion
42 | door a = abn("42")
43 | door f = jajab("3.14")
44 | door s = qoraal(100)
45 | door b = bool(0)
46 |
47 | // List and Object creation
48 | door l = teed(1, 2, 3)
49 | door o = walax(name: "Ayaan", age: 20)
50 |
51 | // Math rounding
52 | qor("Floor: " + daji(4.8))
53 | qor("Ceil: " + kor(4.2))
54 |
55 | // Random number
56 | door r = xul(1, 6)
57 | qor("Random: " + r)
58 | ```
59 |
60 | ---
61 |
62 | Soplang built-ins make code expressive, compact, and accessible in your own language.
63 |
--------------------------------------------------------------------------------
/examples/38_string_startswith.sop:
--------------------------------------------------------------------------------
1 | // Test: String startsWith Method (bilow)
2 | // This test demonstrates the bilow() method which checks if a string starts with a given substring
3 |
4 | qor("Testing string startsWith method (bilow):")
5 |
6 | // Basic example from task definition
7 | door magac = "Barwaaqo"
8 | door x = magac.bilow("Bar") // run
9 | door y = magac.bilow("waa") // been
10 |
11 | qor("")
12 | qor("Basic example:")
13 | qor(" magac = Barwaaqo")
14 | qor(" magac.bilow(Bar) = " + x) // Should be run
15 | qor(" magac.bilow(waa) = " + y) // Should be been
16 |
17 | // More test cases
18 | qor("")
19 | qor("More test cases:")
20 |
21 | // Complete string match
22 | door text1 = "Hello"
23 | qor(" Hello.bilow(Hello) = " + text1.bilow("Hello")) // Should be run
24 |
25 | // Case sensitivity
26 | door text2 = "Hello World"
27 | qor(" Hello World.bilow(hello) = " + text2.bilow("hello")) // Should be been (case sensitive)
28 | qor(" Hello World.bilow(Hello) = " + text2.bilow("Hello")) // Should be run
29 |
30 | // Empty strings (edge cases)
31 | door text3 = ""
32 | door text4 = "Something"
33 | qor("")
34 | qor("Empty string edge cases:")
35 | qor(" Empty string.bilow(empty) = " + text3.bilow("")) // Should be run (empty string starts with empty string)
36 | qor(" Something.bilow(empty) = " + text4.bilow("")) // Should be run (any string starts with empty string)
37 | qor(" Empty string.bilow(x) = " + text3.bilow("x")) // Should be been (empty string doesn't start with non-empty)
38 |
39 | // Practical examples
40 | qor("")
41 | qor("Practical examples:")
42 |
43 | // Check URL protocols
44 | door url1 = "https://example.com"
45 | door url2 = "http://example.org"
46 | door url3 = "ftp://files.net"
47 |
48 | qor(" URL protocol checking:")
49 | qor(" " + url1 + " starts with https:// " + url1.bilow("https://"))
50 | qor(" " + url2 + " starts with https:// " + url2.bilow("https://"))
51 | qor(" " + url3 + " starts with ftp:// " + url3.bilow("ftp://"))
52 |
53 | // Email domain validation
54 | door email1 = "user@example.com"
55 | door email2 = "admin@company.org"
56 | qor("")
57 | qor(" Email username checking:")
58 | qor(" " + email1 + " starts with user@ " + email1.bilow("user@"))
59 | qor(" " + email2 + " starts with admin@ " + email2.bilow("admin@"))
60 |
61 | // File extension checking (negative examples)
62 | door filename1 = "document.pdf"
63 | door filename2 = "image.jpg"
64 | qor("")
65 | qor(" Filename prefix checking:")
66 | qor(" " + filename1 + " starts with doc " + filename1.bilow("doc"))
67 | qor(" " + filename2 + " starts with img " + filename2.bilow("img"))
68 |
69 | qor("")
70 | qor("String startsWith tests completed!")
71 |
--------------------------------------------------------------------------------
/src/components/DocNavigation.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import Link from "next/link";
3 | import { HiArrowLeft, HiArrowRight } from "react-icons/hi";
4 |
5 | interface DocNavigationProps {
6 | prevPage?: {
7 | href: string;
8 | title?: string;
9 | description?: string;
10 | hidden?: boolean; // Add this property to hide the previous link
11 | };
12 | nextPage?: {
13 | href: string;
14 | title: string;
15 | description: string;
16 | };
17 | className?: string;
18 | }
19 |
20 | const DocNavigation: React.FC = ({ prevPage, nextPage, className = "" }) => {
21 | return (
22 | <>
23 |
24 |
25 | {/*
Continue Learning
26 |
Navigate through the Soplang documentation to learn more:
*/}
27 |
28 | {prevPage && !prevPage.hidden && (
29 |
33 |
34 |
35 |
36 |
37 |
{prevPage.title}
38 |
{prevPage.description}
39 |
40 |
41 | )}
42 | {nextPage && (
43 |
49 |
50 |
{nextPage.title}
51 |
{nextPage.description}
52 |
53 |
54 |
55 |
56 |
57 | )}
58 |
59 |
60 | >
61 | );
62 | };
63 |
64 | export default DocNavigation;
65 |
--------------------------------------------------------------------------------
/examples/26_list_slice.sop:
--------------------------------------------------------------------------------
1 | // Test: List Slice (jar) Method
2 | // This test demonstrates the usage of the jar() method for getting slices of lists
3 |
4 | qor("Testing list slice (jar) method:")
5 |
6 | // Create a sample list
7 | teed magacyo = ["Axmed", "Barwaaqo", "Cali", "Deeqa", "Ergada"]
8 | qor(" Original list: " + magacyo)
9 |
10 | // Basic slicing
11 | qor("Basic slicing:")
12 | teed qayb1 = magacyo.jar(1, 3)
13 | qor(" magacyo.jar(1, 3): " + qayb1) // Should be ["Barwaaqo", "Cali"]
14 | // Confirm original list is unchanged
15 | qor(" Original list after slicing: " + magacyo)
16 |
17 | // Slice to the end
18 | qor("Slicing to the end:")
19 | teed qayb2 = magacyo.jar(2, magacyo.dherer())
20 | qor(" magacyo.jar(2, magacyo.dherer()): " + qayb2) // Should be ["Cali", "Deeqa", "Ergada"]
21 |
22 | // Slice from the beginning
23 | qor("Slicing from the beginning:")
24 | teed qayb3 = magacyo.jar(0, 2)
25 | qor(" magacyo.jar(0, 2): " + qayb3) // Should be ["Axmed", "Barwaaqo"]
26 |
27 | // Using negative indices
28 | qor("Using negative indices:")
29 | teed qayb4 = magacyo.jar(-2, magacyo.dherer())
30 | qor(" magacyo.jar(-2, magacyo.dherer()): " + qayb4) // Should be ["Deeqa", "Ergada"]
31 |
32 | // Empty slice (start equals end)
33 | qor("Empty slice (start equals end):")
34 | teed qayb5 = magacyo.jar(2, 2)
35 | qor(" magacyo.jar(2, 2): " + qayb5) // Should be []
36 |
37 | // Out of range indices
38 | qor("Out of range indices:")
39 | teed qayb6 = magacyo.jar(10, 20)
40 | qor(" magacyo.jar(10, 20): " + qayb6) // Should be []
41 |
42 | teed qayb7 = magacyo.jar(-10, 2)
43 | qor(" magacyo.jar(-10, 2): " + qayb7) // Should be ["Axmed", "Barwaaqo"]
44 |
45 | // Edge cases
46 | qor("Edge cases:")
47 | // End index less than start index
48 | teed qayb8 = magacyo.jar(3, 1)
49 | qor(" magacyo.jar(3, 1): " + qayb8) // Should be []
50 |
51 | // Slice the entire list
52 | teed qayb9 = magacyo.jar(0, magacyo.dherer())
53 | qor(" magacyo.jar(0, magacyo.dherer()): " + qayb9)
54 | qor(" Is it a new list (not the same reference)? " + (qayb9 != magacyo))
55 |
56 | // Practical example: pagination
57 | qor("Practical example: pagination")
58 | teed titirada = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
59 | abn bogag = 3 // items per page
60 | abn bogNumber = 2 // page 2 (0-indexed)
61 |
62 | teed bogHada = titirada.jar(bogNumber * bogag, (bogNumber + 1) * bogag)
63 | qor(" Items per page: " + bogag)
64 | qor(" Page " + (bogNumber + 1) + ": " + bogHada) // Should be [7, 8, 9]
65 |
66 | // Working with other data types
67 | qor("Working with different data types:")
68 | teed mixed = [10, "Somali", run, [1, 2], {name: "Soplang"}]
69 | teed qayb10 = mixed.jar(1, 4)
70 | qor(" Mixed list: " + mixed)
71 | qor(" mixed.jar(1, 4): " + qayb10) // Should be ["Somali", true, [1, 2]]
72 |
73 | qor("List slice tests completed!")
74 |
--------------------------------------------------------------------------------
/examples/14_comparison_assignment.sop:
--------------------------------------------------------------------------------
1 | // Test: Comparison Assignment
2 | // This test focuses on assigning the results of comparison operations to variables
3 |
4 | qor("Testing comparison operations in assignments:")
5 |
6 | // Integer comparisons
7 | qor("Integer comparisons:")
8 | abn a = 5
9 | abn b = 3
10 | qor(" a = " + a + ", b = " + b)
11 |
12 | // Direct integer comparison assignments with door type
13 | door result1 = (a > b)
14 | qor(" door result1 = a > b: " + result1)
15 |
16 | door result2 = (a < b)
17 | qor(" door result2 = a < b: " + result2)
18 |
19 | door result3 = (a == b)
20 | qor(" door result3 = a == b: " + result3)
21 |
22 | door result4 = (a != b)
23 | qor(" door result4 = a != b: " + result4)
24 |
25 | door result5 = (a >= b)
26 | qor(" door result5 = a >= b: " + result5)
27 |
28 | door result6 = (a <= b)
29 | qor(" door result6 = a <= b: " + result6)
30 |
31 | // Decimal comparisons
32 | qor("\nDecimal comparisons:")
33 | jajab x = 5.5
34 | jajab y = 3.25
35 | qor(" x = " + x + ", y = " + y)
36 |
37 | // Direct decimal comparison assignments with door type
38 | door result7 = (x > y)
39 | qor(" door result7 = x > y: " + result7)
40 |
41 | door result8 = (x < y)
42 | qor(" door result8 = x < y: " + result8)
43 |
44 | door result9 = (x == y)
45 | qor(" door result9 = x == y: " + result9)
46 |
47 | door result10 = (x != y)
48 | qor(" door result10 = x != y: " + result10)
49 |
50 | // Mixed type comparisons
51 | qor("\nMixed integer and decimal comparisons:")
52 | door result11 = (a > y)
53 | qor(" door result11 = a > y: " + result11)
54 |
55 | door result12 = (x == a)
56 | qor(" door result12 = x == a: " + result12)
57 |
58 | // Test with bool (boolean) type
59 | qor("\nBoolean type assignments:")
60 | bool isGreater = (a > b)
61 | qor(" bool isGreater = a > b: " + isGreater)
62 |
63 | bool isLess = (a < b)
64 | qor(" bool isLess = a < b: " + isLess)
65 |
66 | bool isEqual = (a == b)
67 | qor(" bool isEqual = a == b: " + isEqual)
68 |
69 | bool isNotEqual = (a != b)
70 | qor(" bool isNotEqual = a != b: " + isNotEqual)
71 |
72 | bool isDecimalGreater = (x > y)
73 | qor(" bool isDecimalGreater = x > y: " + isDecimalGreater)
74 |
75 | // Test with complex expressions
76 | qor("\nComplex expressions:")
77 | door complex1 = ((a > b) && (a != b))
78 | qor(" door complex1 = (a > b) && (a != b): " + complex1)
79 |
80 | door complex2 = ((a < b) || (a == 5))
81 | qor(" door complex2 = (a < b) || (a == 5): " + complex2)
82 |
83 | door complex3 = ((x > y) && (a == 5))
84 | qor(" door complex3 = (x > y) && (a == 5): " + complex3)
85 |
86 | // Test with variable reassignment
87 | qor("\nVariable reassignment:")
88 | door test = been
89 | qor(" Initial test value: " + test)
90 | test = a > b
91 | qor(" After test = a > b: " + test)
92 | test = x < y
93 | qor(" After test = x < y: " + test)
94 |
--------------------------------------------------------------------------------
/md/info.md:
--------------------------------------------------------------------------------
1 | # Soplang – Brief Information
2 |
3 | **Soplang** (short for Somali Programming Language) is a modern, general-purpose programming language designed and developed by **Mr Sharafdin** (Sharafdin Yusuf Sharafdin). It allows Somali speakers to write code in their native language using Somali keywords and expressions, making programming more intuitive and accessible.
4 |
5 | ## Tagline
6 | **Soplang is a Somali-first programming language that makes coding intuitive, inclusive, and accessible for Somali peoples.**
7 |
8 | ## Motto
9 | **Dhis Software Adigoo Adeegsanaya Afkaaga Hooyo!**
10 |
11 | ## Language Goals
12 | - **Simplicity**
13 | - **Education**
14 | - **Localization**
15 | - **Accessibility**
16 |
17 | ## Long-Term Mission
18 | Soplang is a general-purpose programming language designed entirely in Somali. Its long-term mission is to empower developers to build anything — from websites and mobile apps to data tools and native software — using their mother tongue.
19 |
20 | ## Highlights of Soplang 2.0
21 | - Dual typing: dynamic (`door`) and static (`abn`, `jajab`, `qoraal`, `bool`, etc.)
22 | - Rich control flow: `haddii`, `haddii_kale`, `ugudambeyn`, `dooro`, `xaalad`, `kuceli`, `intay`, `jooji`, `soco`
23 | - Somali-based standard library for math, file system, networking, and time
24 | - Built-in methods for lists, objects, strings, and type conversion
25 | - Tools: CLI (`sop`), REPL, VS Code extension
26 | - Current backend: Python-based interpreter
27 | - Compiler backend (Rust) is in development
28 |
29 | ## Updated Keywords & Built-in Methods
30 |
31 | ### Types
32 | - `abn` (integer), `jajab` (float), `qoraal` (string), `bool` (boolean), `teed` (list), `walax` (object)
33 |
34 | ### Control Flow
35 | - `haddii`, `haddii_kale`, `ugudambeyn`, `dooro`, `xaalad`, `kuceli`, `intay`, `jooji`, `soco`
36 |
37 | ### Functions
38 | - `hawl` (function), `celi` (return)
39 |
40 | ### Constants
41 | - `madoor` (constant declaration)
42 |
43 | ### Built-in Functions
44 | - `qor`, `gelin`, `nooc`, `abn`, `qoraal`, `bool`, `teed`, `walax`, `dherer`, `xul`, `daji`, `kor`
45 |
46 | ### List Methods
47 | - `dherer()`, `kudar()`, `kasaar()`, `aaddin()`, `shaandhee()`, `muuji()`, `rog()`, `habee()`, `jar()`, `nuqul()`, `nadiifi()`
48 |
49 | ### Object Methods
50 | - `fure()`, `qiime()`, `lamaane()`, `leeyahay()`, `tir()`, `kudar()`, `nuqul()`, `nadiifi()`
51 |
52 | ### String Methods
53 | - `qeybi()`, `beddel()`, `jar()`, `leeyahay()`, `dhamaad()`, `bilow()`, `kudar()`
54 |
55 | ## Community & Licensing
56 | - Open source under the **MIT License**
57 | - Maintained by the **Soplang Software Foundation**
58 | - Everyone can contribute
59 |
60 | ## Core Contributors
61 | - Mr Sharafdin (creator)
62 | - Omar Tood
63 | - Ismail Ainte
64 | - Shiine
65 | - Mo Elkensi
66 |
67 | ## Contact & Links
68 | - Website: [soplang.org](https://soplang.org)
69 | - Email: info@soplang.org
70 | - GitHub: [github.com/soplang/soplang](https://github.com/soplang/soplang)
71 | - Facebook & X: @soplangorg
72 | - LinkedIn: soplang
73 |
--------------------------------------------------------------------------------
/examples/40_string_join.sop:
--------------------------------------------------------------------------------
1 | // Test: String Join Method (kudar)
2 | // This test demonstrates the kudar() method which joins a list of strings with a separator
3 |
4 | qor("Testing string join method (kudar):")
5 |
6 | // Basic example from task definition
7 | door magacyo = ["Ayaan", "Cali", "Zahra"]
8 | door natiijo = ", ".kudar(magacyo)
9 |
10 | qor("")
11 | qor("Basic example:")
12 | qor(" Names: " + magacyo)
13 | qor(" Joined with comma: " + natiijo) // Should be "Ayaan, Cali, Zahra"
14 |
15 | // Empty list test
16 | door empty_list = []
17 | door empty_result = "-".kudar(empty_list)
18 | qor("")
19 | qor("Empty list test:")
20 | qor(" Empty list joined with dash: '" + empty_result + "'") // Should be ""
21 |
22 | // Single item list
23 | door single_list = ["Warsame"]
24 | door single_result = "...".kudar(single_list)
25 | qor("")
26 | qor("Single item list:")
27 | qor(" Single item list joined with dots: " + single_result) // Should be "Warsame" with no separator
28 |
29 | // Different types of separators
30 | door fruits = ["Tufaax", "Moos", "Cambe"]
31 | door with_comma = ", ".kudar(fruits)
32 | door with_dash = " - ".kudar(fruits)
33 | door with_empty = "".kudar(fruits)
34 | qor("")
35 | qor("Different separators:")
36 | qor(" With comma: " + with_comma) // Should be "Tufaax, Moos, Cambe"
37 | qor(" With dash: " + with_dash) // Should be "Tufaax - Moos - Cambe"
38 | qor(" With empty string: " + with_empty) // Should be "TufaaxMoosCambe"
39 |
40 | // Multiple newlines for clarity
41 | qor("")
42 | qor("Newline separator:")
43 | // Using direct newline
44 | door items = ["Item 1", "Item 2", "Item 3"]
45 | qor(" Items on separate lines:")
46 | qor("Item 1")
47 | qor("Item 2")
48 | qor("Item 3")
49 |
50 | // Practical examples
51 | qor("")
52 | qor("Practical examples:")
53 |
54 | // CSV line generation
55 | door data = ["2023-06-15", "Ahmed", "Somalia", "30"]
56 | door csv_line = ",".kudar(data)
57 | qor(" CSV line generation: " + csv_line) // Should be "2023-06-15,Ahmed,Somalia,30"
58 |
59 | // URL building
60 | door url_parts = ["https://example.com", "api", "v1", "users", "123"]
61 | door url = "/".kudar(url_parts)
62 | qor(" URL building: " + url) // Should be "https://example.com/api/v1/users/123"
63 |
64 | // File path construction
65 | door path_parts = ["home", "user", "documents", "report.pdf"]
66 | door path = "/".kudar(path_parts)
67 | qor(" File path construction: " + path) // Should be "home/user/documents/report.pdf"
68 |
69 | // HTML list generation
70 | door list_items = ["Hordhac", "Faahfaahin", "Gunaanad"]
71 | door html_list = "".kudar(list_items) + " "
72 | qor(" HTML list generation: " + html_list) // Should be "HordhacFaahfaahin Gunaanad "
73 |
74 | // Sentence construction
75 | door words = ["Soplang", "waa", "luqad", "cusub", "oo", "waxtar", "leh"]
76 | door sentence = " ".kudar(words) + "."
77 | qor(" Sentence construction: " + sentence) // Should be "Soplang waa luqad cusub oo waxtar leh."
78 |
79 | qor("")
80 | qor("String join tests completed!")
81 |
--------------------------------------------------------------------------------
/src/app/docs/input-and-output/page.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import CodeWindow from "@/components/CodeWindow";
3 | import DocNavigation from "@/components/DocNavigation";
4 |
5 | export const metadata = {
6 | title: "Input and Output in Soplang",
7 | description:
8 | "Sida loo isticmaalo qor() iyo gelin() si aad u daabacdo wax soo saar ama u akhrido gelinta isticmaalaha ee Soplang.",
9 | };
10 |
11 | export default function InputOutputPage() {
12 | return (
13 |
14 |
Input and Output in Soplang
15 |
16 | Soplang waxay isticmaashaa shaqooyin-dhexdeed fudud si loo soo bandhigo wax soo saar iyo
17 | in lagu akhriyo gelinta isticmaalaha.
18 |
19 |
20 | {/* 🖨️ qor() – Print to Console */}
21 |
22 | 🖨️ qor() – Print to Console
23 |
24 | Adeegso qor() si aad u muujiso
25 | qiimayaal ama xarfo (strings) shaashadda.
26 |
27 |
33 |
34 |
35 |
36 | {/* ⌨️ gelin() – Read from User Input */}
37 |
57 |
58 | {/* Navigation */}
59 |
72 |
73 | );
74 | }
75 |
--------------------------------------------------------------------------------
/temp_backup/src/components/ThemeProvider.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import { createContext, useContext, useEffect, useState } from "react";
4 |
5 | type Theme = "dark" | "light" | "system";
6 |
7 | type ThemeProviderProps = {
8 | children: React.ReactNode;
9 | defaultTheme?: Theme;
10 | attribute?: string;
11 | enableSystem?: boolean;
12 | };
13 |
14 | type ThemeProviderState = {
15 | theme: Theme;
16 | setTheme: (theme: Theme) => void;
17 | };
18 |
19 | const initialState: ThemeProviderState = {
20 | theme: "system",
21 | setTheme: () => null,
22 | };
23 |
24 | const ThemeProviderContext = createContext(initialState);
25 |
26 | export function ThemeProvider({
27 | children,
28 | defaultTheme = "system",
29 | attribute = "class",
30 | enableSystem = true,
31 | ...props
32 | }: ThemeProviderProps) {
33 | const [theme, setTheme] = useState(defaultTheme);
34 |
35 | useEffect(() => {
36 | const root = window.document.documentElement;
37 | root.classList.remove("light", "dark");
38 |
39 | if (theme === "system" && enableSystem) {
40 | const systemTheme = window.matchMedia("(prefers-color-scheme: dark)")
41 | .matches
42 | ? "dark"
43 | : "light";
44 | root.classList.add(systemTheme);
45 | return;
46 | }
47 |
48 | root.classList.add(theme);
49 | }, [theme, enableSystem]);
50 |
51 | const value = {
52 | theme,
53 | setTheme: (theme: Theme) => {
54 | setTheme(theme);
55 | // Save theme preference to localStorage
56 | localStorage.setItem("theme", theme);
57 | },
58 | };
59 |
60 | // Initialize theme from localStorage if available
61 | useEffect(() => {
62 | const savedTheme = localStorage.getItem("theme") as Theme | null;
63 | if (savedTheme) {
64 | setTheme(savedTheme);
65 | }
66 | }, []);
67 |
68 | // Listen for system theme changes
69 | useEffect(() => {
70 | if (!enableSystem) return;
71 |
72 | const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
73 |
74 | const handleChange = () => {
75 | if (theme === "system") {
76 | const root = window.document.documentElement;
77 | root.classList.remove("light", "dark");
78 | root.classList.add(mediaQuery.matches ? "dark" : "light");
79 | }
80 | };
81 |
82 | mediaQuery.addEventListener("change", handleChange);
83 | return () => mediaQuery.removeEventListener("change", handleChange);
84 | }, [theme, enableSystem]);
85 |
86 | return (
87 |
88 |
89 | {children}
90 |
91 |
92 | );
93 | }
94 |
95 | export const useTheme = () => {
96 | const context = useContext(ThemeProviderContext);
97 | if (context === undefined) {
98 | throw new Error("useTheme must be used within a ThemeProvider");
99 | }
100 | return context;
101 | };
--------------------------------------------------------------------------------
/examples/12_object_operations.sop:
--------------------------------------------------------------------------------
1 | // Test: Object Operations
2 | // This test checks if object operations work properly
3 |
4 | qor("Testing object operations:")
5 |
6 | // Creating objects
7 | walax empty_obj = {}
8 | walax person = {
9 | magac: "Asha",
10 | da: 30,
11 | magaalo: "Muqdisho"
12 | }
13 |
14 | qor(" Empty object: " + empty_obj)
15 | qor(" Person object: " + person)
16 | qor(" Type of person: " + nooc(person))
17 |
18 | // Accessing properties
19 | qor(" Name: " + person.magac)
20 | qor(" Age: " + person.da)
21 | qor(" City: " + person.magaalo)
22 |
23 | // Modifying properties using dot notation
24 | person.da = 31
25 | qor(" After changing age: " + person)
26 |
27 | // Adding new properties using dot notation
28 | person.shaqo = "Barnaamij Samayne"
29 | qor(" After adding job: " + person)
30 |
31 | // Nested objects
32 | walax address = {
33 | city: "Muqdisho",
34 | country: "Soomaaliya",
35 | district: "Hodan"
36 | }
37 |
38 | walax employee = {
39 | name: "Mohamed",
40 | age: 28,
41 | address: address
42 | }
43 |
44 | qor(" Employee with nested address: " + employee)
45 | qor(" Employee's district: " + employee.address.district)
46 |
47 | // Object keys
48 | door keys = person.fure()
49 | qor(" Object keys: " + keys)
50 | qor(" Type of keys: " + nooc(keys))
51 |
52 | // Debug - Print first few keys if they exist
53 | haddii (keys.dherer() > 0) {
54 | qor(" First key: " + keys[0])
55 | }
56 |
57 | // Check if property exists
58 | bool has_job = person.leeyahay("shaqo")
59 | qor(" Does person have 'shaqo'? " + has_job)
60 |
61 | bool has_email = person.leeyahay("email")
62 | qor(" Does person have 'email'? " + has_email)
63 |
64 | // Removing properties
65 | person.tir("shaqo")
66 | qor(" After removing job: " + person)
67 |
68 | // Merging objects
69 | walax obj1 = {a: 1, b: 2}
70 | walax obj2 = {c: 3, d: 4}
71 | walax merged = obj1.kudar(obj2)
72 | qor(" obj1: " + obj1)
73 | qor(" obj2: " + obj2)
74 | qor(" Merged object: " + merged)
75 |
76 | // Testing additional nested property access
77 | qor("\nTesting additional nested property access:")
78 |
79 | // Create a company object with nested properties
80 | walax company = {
81 | name: "Somali Tech",
82 | location: {
83 | city: "Mogadishu",
84 | address: "Innovation Avenue"
85 | }
86 | }
87 |
88 | // Test accessing nested properties
89 | qor(" Company name: " + company.name)
90 | qor(" Company city: " + company.location.city)
91 | qor(" Company address: " + company.location.address)
92 |
93 | // Test updating nested properties using dot notation
94 | company.location.city = "Hargeisa"
95 | qor(" Updated city: " + company.location.city)
96 |
97 | // Test object with array
98 | walax team = {
99 | members: [
100 | {name: "Ali", role: "Developer"},
101 | {name: "Fatima", role: "Designer"}
102 | ]
103 | }
104 |
105 | // Access array elements in object
106 | qor(" First team member: " + team.members[0].name)
107 | qor(" Second team member role: " + team.members[1].role)
108 |
--------------------------------------------------------------------------------
/examples/42_universal_length.sop:
--------------------------------------------------------------------------------
1 | // Test: Universal Length Function (dherer)
2 | // This test demonstrates dherer() to get length of different data types
3 |
4 | qor("Testing universal length function (dherer):")
5 |
6 | // Example from task specification
7 | door l = [1, 2, 3]
8 | door t = "Soplang"
9 | door o = {magac: "Cali"}
10 |
11 | qor("Basic examples:")
12 | qor(" dherer([1, 2, 3]): " + dherer(l)) // 3
13 | qor(" dherer('Soplang'): " + dherer(t)) // 7
14 | qor(" dherer(object o): " + dherer(o)) // 1
15 |
16 | qor("")
17 | qor("More list examples:")
18 | // Empty list
19 | door emptyList = []
20 | qor(" Empty list length: " + dherer(emptyList)) // 0
21 |
22 | // Nested list
23 | door nestedList = [1, [2, 3], 4]
24 | qor(" Nested list length: " + dherer(nestedList)) // 3 (counts top-level items only)
25 |
26 | // List with different types
27 | door mixedList = [1, "two", [3, 4], {five: 5}]
28 | qor(" Mixed list length: " + dherer(mixedList)) // 4
29 |
30 | qor("")
31 | qor("More string examples:")
32 | // Empty string
33 | door emptyString = ""
34 | qor(" Empty string length: " + dherer(emptyString)) // 0
35 |
36 | // String with spaces
37 | door stringWithSpaces = "Hello world"
38 | qor(" String with spaces length: " + dherer(stringWithSpaces)) // 11
39 |
40 | // String with special characters
41 | door specialChars = "Waa^&*123"
42 | qor(" String with special chars length: " + dherer(specialChars)) // 10
43 |
44 | qor("")
45 | qor("More object examples:")
46 | // Empty object
47 | door emptyObject = {}
48 | qor(" Empty object length: " + dherer(emptyObject)) // 0
49 |
50 | // Object with multiple properties
51 | door person = {magac: "Ahmed", da: 30, magaalada: "Mogadishu"}
52 | qor(" Object with multiple properties: " + dherer(person)) // 3
53 |
54 | // Nested object (only counts top-level properties)
55 | door nestedObject = {info: {x: 1, y: 2}, value: 42}
56 | qor(" Nested object length: " + dherer(nestedObject)) // 2
57 |
58 | qor("")
59 | qor("Practical applications:")
60 |
61 | // Using dherer in a loop
62 | teed numbers = [10, 20, 30, 40, 50]
63 | abn sum = 0
64 | kuceli (i 0 ilaa dherer(numbers) - 1) {
65 | sum = sum + numbers[i]
66 | }
67 | qor(" Sum of numbers using loop and dherer(): " + sum) // 150
68 |
69 | // String truncation
70 | door longString = "Soplang waa luqad cusub oo waxtar leh"
71 | door maxLength = 20
72 | door truncated = ""
73 |
74 | haddii (dherer(longString) > maxLength) {
75 | truncated = longString.jar(0, maxLength) + "..."
76 | } ugudambeyn {
77 | truncated = longString
78 | }
79 | qor(" Truncated string: " + truncated) // "Soplang waa luqad cu..."
80 |
81 | // Object property count check
82 | door config = {debug: run, verbose: been, logLevel: "info"}
83 | haddii (dherer(config) > 0) {
84 | qor(" Config has " + dherer(config) + " settings")
85 | } ugudambeyn {
86 | qor(" Config is empty")
87 | }
88 |
89 | qor("")
90 | qor("Error handling test:")
91 | qor(" Note: The following line would cause an error if uncommented:")
92 | qor(" // dherer(123) - Would throw error as numbers are not supported")
93 |
94 | qor("")
95 | qor("Universal length function tests completed!")
96 |
--------------------------------------------------------------------------------
/examples/39_string_replace.sop:
--------------------------------------------------------------------------------
1 | // Test: String Replace Method (beddel)
2 | // This test demonstrates the beddel() method which replaces part of a string with another substring
3 |
4 | qor("Testing string replace method (beddel):")
5 |
6 | // Basic example from task definition
7 | door text = "Soplang waa fudud"
8 | door natiijo = text.beddel("fudud", "xoogan")
9 |
10 | qor("")
11 | qor("Basic example:")
12 | qor(" Original: " + text)
13 | qor(" After replacing 'fudud' with 'xoogan': " + natiijo) // Should be "Soplang waa xoogan"
14 |
15 | // Test when the target doesn't exist
16 | door text1 = "Hello World"
17 | door result1 = text1.beddel("Universe", "Galaxy")
18 | qor("")
19 | qor("Target doesn't exist:")
20 | qor(" Original: " + text1)
21 | qor(" After replacing 'Universe' with 'Galaxy': " + result1) // Should remain unchanged "Hello World"
22 |
23 | // Test case sensitivity
24 | door text2 = "Hello world, hello everyone"
25 | door result2 = text2.beddel("hello", "Howdy")
26 | qor("")
27 | qor("Case sensitivity:")
28 | qor(" Original: " + text2)
29 | qor(" After replacing 'hello' with 'Howdy': " + result2) // Should replace second "hello" -> "Hello world, Howdy everyone"
30 |
31 | // Test replacing only first occurrence
32 | door text3 = "la la la, la la la"
33 | door result3 = text3.beddel("la", "ba")
34 | qor("")
35 | qor("Replace only first occurrence:")
36 | qor(" Original: " + text3)
37 | qor(" After replacing first 'la' with 'ba': " + result3) // Should be "ba la la, la la la"
38 |
39 | // Test with empty strings
40 | door text4 = "Empty test"
41 | door result4a = text4.beddel("", "Something")
42 | door result4b = text4.beddel("Empty", "")
43 | qor("")
44 | qor("Empty string tests:")
45 | qor(" Original: " + text4)
46 | qor(" Replace empty string with 'Something': " + result4a) // Behavior may vary, but likely unchanged
47 | qor(" Replace 'Empty' with empty string: " + result4b) // Should be " test"
48 |
49 | // Practical examples
50 | qor("")
51 | qor("Practical examples:")
52 |
53 | // URL path manipulation
54 | door url = "https://example.com/oldpath/page.html"
55 | door newUrl = url.beddel("/oldpath/", "/newpath/")
56 | qor(" URL path update:")
57 | qor(" Original: " + url)
58 | qor(" Updated: " + newUrl) // Should be "https://example.com/newpath/page.html"
59 |
60 | // Formatting numbers
61 | door number = "1000000"
62 | door formatted = number.beddel("000", ",000")
63 | qor("")
64 | qor(" Number formatting:")
65 | qor(" Original: " + number)
66 | qor(" Formatted: " + formatted) // Should be "1,000000" (only first occurrence)
67 |
68 | // Censoring content
69 | door message = "This password is secret123, don't share it"
70 | door censored = message.beddel("secret123", "********")
71 | qor("")
72 | qor(" Censoring sensitive data:")
73 | qor(" Original: " + message)
74 | qor(" Censored: " + censored) // Should be "This password is ********, don't share it"
75 |
76 | // Correcting typos
77 | door typo = "Salaan, Aduunka!"
78 | door corrected = typo.beddel("Aduunka", "Adduunka")
79 | qor("")
80 | qor(" Correcting typos:")
81 | qor(" Original: " + typo)
82 | qor(" Corrected: " + corrected) // Should be "Salaan, Adduunka!"
83 |
84 | qor("")
85 | qor("String replace tests completed!")
86 |
--------------------------------------------------------------------------------
/examples/09_switch_case.sop:
--------------------------------------------------------------------------------
1 | // Example 9: Switch-Case Statements
2 | // This example demonstrates the usage of dooro (switch) and xaalad (case) statements
3 |
4 | qor("=====================================")
5 | qor("Switch-Case Statements (dooro/xaalad)")
6 | qor("=====================================")
7 |
8 | // Example 1: Basic switch with integer
9 | qor("\n1. Basic switch with integer:")
10 | abn number = 2
11 | qor("Testing with number = " + number)
12 |
13 | dooro (number) {
14 | xaalad 1 {
15 | qor("Hal (One)")
16 | }
17 | xaalad 2 {
18 | qor("Laba (Two)")
19 | }
20 | xaalad 3 {
21 | qor("Saddex (Three)")
22 | }
23 | ugudambeyn {
24 | qor("abn kale (Another number)")
25 | }
26 | }
27 |
28 | // Example 2: Switch with strings
29 | qor("\n2. Switch with strings:")
30 | qoraal language = "Somali"
31 | qor("Testing with language = " + language)
32 |
33 | dooro (language) {
34 | xaalad "English" {
35 | qor("Hello, World!")
36 | }
37 | xaalad "Somali" {
38 | qor("Salaan, Adduunka!")
39 | }
40 | xaalad "Spanish" {
41 | qor("¡Hola, Mundo!")
42 | }
43 | ugudambeyn {
44 | qor("Language not recognized")
45 | }
46 | }
47 |
48 | // Example 3: Switch with expressions
49 | qor("\n3. Switch with expressions:")
50 | abn x = 10
51 | abn y = 20
52 | qor("Testing with x = " + x + " and y = " + y)
53 |
54 | dooro (x + y) {
55 | xaalad 10 {
56 | qor("Sum is 10")
57 | }
58 | xaalad 30 {
59 | qor("Sum is 30")
60 | }
61 | xaalad 50 {
62 | qor("Sum is 50")
63 | }
64 | ugudambeyn {
65 | qor("Sum is " + (x + y))
66 | }
67 | }
68 |
69 | // Example 4: Switch with decimal values
70 | qor("\n4. Switch with decimal values:")
71 | jajab price = 19.99
72 | qor("Testing with price = " + price)
73 |
74 | dooro (price) {
75 | xaalad 9.99 {
76 | qor("Budget item")
77 | }
78 | xaalad 19.99 {
79 | qor("Standard item")
80 | }
81 | xaalad 29.99 {
82 | qor("Premium item")
83 | }
84 | ugudambeyn {
85 | qor("Custom priced item")
86 | }
87 | }
88 |
89 | // Example 5: Nested switch statements
90 | qor("\n5. Nested switch statements:")
91 | abn department = 1
92 | abn level = 2
93 | qor("Testing with department = " + department + " and level = " + level)
94 |
95 | dooro (department) {
96 | xaalad 1 {
97 | qor("Engineering Department")
98 | dooro (level) {
99 | xaalad 1 {
100 | qor("- Junior Engineer")
101 | }
102 | xaalad 2 {
103 | qor("- Senior Engineer")
104 | }
105 | ugudambeyn {
106 | qor("- Management Level")
107 | }
108 | }
109 | }
110 | xaalad 2 {
111 | qor("Marketing Department")
112 | }
113 | ugudambeyn {
114 | qor("Other Department")
115 | }
116 | }
117 |
118 | // Example 6: Switch with boolean expression
119 | qor("\n6. Switch with boolean expression:")
120 | abn score = 85
121 | qor("Testing with score = " + score)
122 |
123 | dooro (score >= 80) {
124 | xaalad run {
125 | qor("High score achieved!")
126 | }
127 | xaalad been {
128 | qor("Keep practicing")
129 | }
130 | }
131 |
132 | qor("\nSwitch-case demonstration completed!")
133 |
--------------------------------------------------------------------------------
/examples/13_type_conversion.sop:
--------------------------------------------------------------------------------
1 | // Test: Type Conversion
2 | // This test checks if type conversion functions work properly
3 |
4 | qor("Testing type conversion:")
5 |
6 | // Integer to string conversion
7 | abn int_value = 42
8 | qoraal int_str = qoraal(int_value)
9 | qor(" Integer to string: " + int_str + " (Type: " + nooc(int_str) + ")")
10 |
11 | // Decimal to string conversion
12 | jajab decimal_value = 3.14159
13 | qoraal decimal_str = qoraal(decimal_value)
14 | qor(" Decimal to string: " + decimal_str + " (Type: " + nooc(decimal_str) + ")")
15 |
16 | // String to integer conversion
17 | qoraal int_string = "123"
18 | abn converted_int = abn(int_string)
19 | qor(" String to integer: " + converted_int + " (Type: " + nooc(converted_int) + ")")
20 |
21 | // String to decimal conversion
22 | qoraal decimal_string = "3.14159"
23 | jajab converted_decimal = jajab(decimal_string)
24 | qor(" String to decimal: " + converted_decimal + " (Type: " + nooc(converted_decimal) + ")")
25 |
26 | // Integer to decimal conversion
27 | abn int_num = 42
28 | jajab decimal_from_int = jajab(int_num)
29 | qor(" Integer to decimal: " + decimal_from_int + " (Type: " + nooc(decimal_from_int) + ")")
30 |
31 | // Decimal to integer conversion (truncation)
32 | jajab decimal_num = 42.75
33 | abn int_from_decimal = abn(decimal_num)
34 | qor(" Decimal to integer (truncation): " + int_from_decimal + " (Type: " + nooc(int_from_decimal) + ")")
35 |
36 | // Boolean to number conversion
37 | abn bool_int_f = abn(been)
38 | abn bool_int_t = abn(run)
39 | qor(" Boolean (been) to integer: " + bool_int_f)
40 | qor(" Boolean (run) to integer: " + bool_int_t)
41 |
42 | jajab bool_decimal_f = jajab(been)
43 | jajab bool_decimal_t = jajab(run)
44 | qor(" Boolean (been) to decimal: " + bool_decimal_f)
45 | qor(" Boolean (run) to decimal: " + bool_decimal_t)
46 |
47 | // String to boolean conversion
48 | bool str_bool_t = bool("been")
49 | bool str_bool_f = bool("run")
50 | qor(" String 'been' to boolean: " + str_bool_t)
51 | qor(" String 'run' to boolean: " + str_bool_f)
52 |
53 | // Number to boolean conversion
54 | bool int_bool_0 = bool(0)
55 | bool int_bool_1 = bool(1)
56 | bool int_bool_42 = bool(42)
57 | qor(" Integer 0 to boolean: " + int_bool_0)
58 | qor(" Integer 1 to boolean: " + int_bool_1)
59 | qor(" Integer 42 to boolean: " + int_bool_42)
60 |
61 | bool decimal_bool_0 = bool(0.0)
62 | bool decimal_bool_1 = bool(1.5)
63 | qor(" Decimal 0.0 to boolean: " + decimal_bool_0)
64 | qor(" Decimal 1.5 to boolean: " + decimal_bool_1)
65 |
66 | // Boolean to string conversion
67 | qoraal bool_str_t = qoraal(been)
68 | qoraal bool_str_f = qoraal(run)
69 | qor(" Boolean (been) to string: " + bool_str_t)
70 | qor(" Boolean (run) to string: " + bool_str_f)
71 |
72 | // List to string conversion
73 | teed test_list = [1, 2, 3, 4.5]
74 | qoraal list_str = qoraal(test_list)
75 | qor(" List to string: " + list_str)
76 |
77 | // Object to string conversion
78 | walax test_obj = {name: "Test", int_value: 42, decimal_value: 3.14}
79 | qoraal obj_str = qoraal(test_obj)
80 | qor(" Object to string: " + obj_str)
81 |
82 | // Invalid conversions (these should fail or return defaults)
83 | // qor(" Invalid string to integer: " + abn("not a number"))
84 | // qor(" Invalid string to decimal: " + jajab("not a number"))
85 | // qor(" Invalid string to boolean: " + bool("not a boolean"))
86 |
--------------------------------------------------------------------------------
/examples/10_functions.sop:
--------------------------------------------------------------------------------
1 | // Test: Functions
2 | // This test checks if functions work properly
3 |
4 | qor("Testing functions (hawl):")
5 |
6 | // Simple function with no parameters or return value
7 | hawl salaan() {
8 | qor(" Salaan, Adduunka!")
9 | }
10 |
11 | qor(" Calling salaan function:")
12 | salaan()
13 |
14 | // Function with integer parameters
15 | hawl isku_dar_integers(x, y) {
16 | celi x + y
17 | }
18 |
19 | qor(" Testing function with integer parameters:")
20 | qor(" isku_dar_integers(5, 7): " + isku_dar_integers(5, 7))
21 | qor(" isku_dar_integers(10, 20): " + isku_dar_integers(10, 20))
22 |
23 | // Function with decimal parameters
24 | hawl isku_dar_decimals(x, y) {
25 | celi x + y
26 | }
27 |
28 | qor(" Testing function with decimal parameters:")
29 | qor(" isku_dar_decimals(5.5, 7.25): " + isku_dar_decimals(5.5, 7.25))
30 | qor(" isku_dar_decimals(10.1, 20.2): " + isku_dar_decimals(10.1, 20.2))
31 |
32 | // Function with string concatenation
33 | hawl isku_dar_strings(str1, str2) {
34 | celi str1 + str2
35 | }
36 |
37 | qor(" Testing function with string parameters:")
38 | qor(" isku_dar_strings('Magac', 'Danbe'): " + isku_dar_strings("Magac", "Danbe"))
39 |
40 | // Function that doubles an integer
41 | hawl laban_jibbaar_integer(num) {
42 | celi num * 2
43 | }
44 |
45 | // Function that doubles a decimal
46 | hawl laban_jibbaar_decimal(num) {
47 | celi num * 2
48 | }
49 |
50 | qor(" Testing functions with specific return types:")
51 | qor(" laban_jibbaar_integer(8): " + laban_jibbaar_integer(8))
52 | qor(" laban_jibbaar_decimal(8.5): " + laban_jibbaar_decimal(8.5))
53 |
54 | // Function with type checking
55 | hawl check_even(num) {
56 | haddii (num % 2 == 0) {
57 | celi run
58 | } ugudambeyn {
59 | celi been
60 | }
61 | }
62 |
63 | qor(" Testing function with type checking:")
64 | qor(" check_even(4): " + check_even(4))
65 | qor(" check_even(7): " + check_even(7))
66 |
67 | // Function with decimal rounding
68 | hawl round_decimal(num) {
69 | abn rounded = abn(num)
70 | celi rounded
71 | }
72 |
73 | qor(" Testing decimal rounding function:")
74 | qor(" round_decimal(4.7): " + round_decimal(4.7))
75 | qor(" round_decimal(9.2): " + round_decimal(9.2))
76 |
77 | // Function with conditional return
78 | hawl get_grade(score) {
79 | haddii (score >= 90) {
80 | celi "A"
81 | } haddii_kale (score >= 80) {
82 | celi "B"
83 | } haddii_kale (score >= 70) {
84 | celi "C"
85 | } haddii_kale (score >= 60) {
86 | celi "D"
87 | } ugudambeyn {
88 | celi "F"
89 | }
90 | }
91 |
92 | qor(" Testing function with conditional return:")
93 | qor(" get_grade(95): " + get_grade(95))
94 | qor(" get_grade(85): " + get_grade(85))
95 | qor(" get_grade(75): " + get_grade(75))
96 | qor(" get_grade(65): " + get_grade(65))
97 | qor(" get_grade(55): " + get_grade(55))
98 |
99 | // Function that works with both integers and decimals
100 | hawl calculate_area(shape, a, b) {
101 | haddii (shape == "rectangle") {
102 | celi a * b
103 | } haddii_kale (shape == "triangle") {
104 | celi 0.5 * a * b
105 | } ugudambeyn {
106 | celi 0
107 | }
108 | }
109 |
110 | qor(" Testing generic calculation function:")
111 | qor(" Rectangle area (integers) calculate_area('rectangle', 5, 10): " + calculate_area("rectangle", 5, 10))
112 | qor(" Triangle area (decimals) calculate_area('triangle', 5.5, 10.5): " + calculate_area("triangle", 5.5, 10.5))
113 |
--------------------------------------------------------------------------------
/examples/15_switch_case.sop:
--------------------------------------------------------------------------------
1 | // Test: Switch-Case Statements
2 | // This test demonstrates the dooro/xaalad (switch/case) syntax
3 |
4 | qor("Testing switch-case (dooro/xaalad) statements:")
5 |
6 | // Simple switch-case with integers
7 | abn number = 2
8 | qor("\n1. Simple switch with integer:")
9 | qor(" number = " + number)
10 |
11 | dooro (number) {
12 | xaalad 1 {
13 | qor(" Hal (One)")
14 | }
15 | xaalad 2 {
16 | qor(" Laba (Two)")
17 | }
18 | xaalad 3 {
19 | qor(" Saddex (Three)")
20 | }
21 | ugudambeyn {
22 | qor(" Waa abn kale (It's another number)")
23 | }
24 | }
25 |
26 | // Switch with strings
27 | qoraal language = "Somali"
28 | qor("\n2. Switch with strings:")
29 | qor(" language = " + language)
30 |
31 | dooro (language) {
32 | xaalad "English" {
33 | qor(" Hello, World!")
34 | }
35 | xaalad "Somali" {
36 | qor(" Salaan, Adduunka!")
37 | }
38 | xaalad "Spanish" {
39 | qor(" ¡Hola, Mundo!")
40 | }
41 | ugudambeyn {
42 | qor(" I don't know that language yet.")
43 | }
44 | }
45 |
46 | // Switch with variable expressions
47 | abn x = 10
48 | abn y = 20
49 | qor("\n3. Switch with expressions:")
50 | qor(" x = " + x + ", y = " + y)
51 |
52 | dooro (x + y) {
53 | xaalad 10 {
54 | qor(" x + y equals 10")
55 | }
56 | xaalad 20 {
57 | qor(" x + y equals 20")
58 | }
59 | xaalad 30 {
60 | qor(" x + y equals 30")
61 | }
62 | ugudambeyn {
63 | qor(" x + y equals " + (x + y))
64 | }
65 | }
66 |
67 | // Switch with decimal values
68 | jajab decimal = 1.5
69 | qor("\n4. Switch with decimal values:")
70 | qor(" decimal = " + decimal)
71 |
72 | dooro (decimal) {
73 | xaalad 1.0 {
74 | qor(" decimal equals 1.0")
75 | }
76 | xaalad 1.5 {
77 | qor(" decimal equals 1.5")
78 | }
79 | xaalad 2.0 {
80 | qor(" decimal equals 2.0")
81 | }
82 | ugudambeyn {
83 | qor(" Unrecognized decimal value")
84 | }
85 | }
86 |
87 | // Nested switch statements
88 | abn outer = 1
89 | abn inner = 2
90 | qor("\n5. Nested switch statements:")
91 | qor(" outer = " + outer + ", inner = " + inner)
92 |
93 | dooro (outer) {
94 | xaalad 1 {
95 | qor(" Outer case is 1")
96 | dooro (inner) {
97 | xaalad 1 {
98 | qor(" Inner case is 1")
99 | }
100 | xaalad 2 {
101 | qor(" Inner case is 2")
102 | }
103 | ugudambeyn {
104 | qor(" Inner case is something else")
105 | }
106 | }
107 | }
108 | xaalad 2 {
109 | qor(" Outer case is 2")
110 | }
111 | ugudambeyn {
112 | qor(" Outer case is something else")
113 | }
114 | }
115 |
116 | // Function returning a value for switch
117 | hawl get_option() {
118 | celi "B"
119 | }
120 |
121 | qor("\n6. Switch with function result:")
122 | qoraal option = get_option()
123 | qor(" option = " + option)
124 |
125 | dooro (option) {
126 | xaalad "A" {
127 | qor(" Option A selected")
128 | }
129 | xaalad "B" {
130 | qor(" Option B selected")
131 | }
132 | xaalad "C" {
133 | qor(" Option C selected")
134 | }
135 | ugudambeyn {
136 | qor(" Unknown option selected")
137 | }
138 | }
139 |
140 | // Testing boolean expressions
141 | bool is_active = run
142 | qor("\n7. Switch with boolean value:")
143 | qor(" is_active = " + is_active)
144 |
145 | dooro (is_active) {
146 | xaalad run {
147 | qor(" The system is active")
148 | }
149 | xaalad been {
150 | qor(" The system is inactive")
151 | }
152 | }
153 |
154 | qor("\nSwitch-case tests completed!")
155 |
--------------------------------------------------------------------------------
/src/styles/soplang-syntax.css:
--------------------------------------------------------------------------------
1 | /**
2 | * Soplang syntax highlighting theme
3 | * Based on VSCode-like styling
4 | */
5 |
6 | code[class*="language-soplang"],
7 | pre[class*="language-soplang"] {
8 | color: #d4d4d4;
9 | font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
10 | direction: ltr;
11 | text-align: left;
12 | white-space: pre;
13 | word-spacing: normal;
14 | word-break: normal;
15 | line-height: 1.5;
16 | tab-size: 4;
17 | hyphens: none;
18 | background: #1e1e1e;
19 | border-radius: 0.3em;
20 | }
21 |
22 | /* Code blocks */
23 | pre[class*="language-soplang"] {
24 | padding: 1em;
25 | margin: 0.5em 0;
26 | overflow: auto;
27 | }
28 |
29 | /* Inline code */
30 | :not(pre) > code[class*="language-soplang"] {
31 | padding: 0.1em 0.3em;
32 | border-radius: 0.3em;
33 | white-space: normal;
34 | }
35 |
36 | .token.comment {
37 | color: #6a9955;
38 | }
39 |
40 | .token.keyword {
41 | color: #569cd6;
42 | }
43 |
44 | .token.string {
45 | color: #ce9178;
46 | }
47 |
48 | .token.function {
49 | color: #dcdcaa;
50 | }
51 |
52 | .token.number {
53 | color: #b5cea8;
54 | }
55 |
56 | .token.boolean {
57 | color: #569cd6;
58 | }
59 |
60 | .token.operator {
61 | color: #d4d4d4;
62 | }
63 |
64 | .token.punctuation {
65 | color: #d4d4d4;
66 | }
67 |
68 | /* Line highlighting */
69 | .line-highlight {
70 | background: rgba(255, 255, 255, 0.1);
71 | }
72 |
73 | /* Line numbers */
74 | .line-numbers .line-numbers-rows {
75 | border-right: 1px solid #999;
76 | }
77 |
78 | .line-numbers-rows > span:before {
79 | color: #999;
80 | }
81 |
82 | /* Match braces */
83 | .token.punctuation.brace-hover,
84 | .token.punctuation.brace-selected {
85 | outline: solid 1px #75a7ca;
86 | }
87 |
88 | /* Code editor window styling */
89 | .code-window {
90 | background: #1e1e1e;
91 | border-radius: 0.5em;
92 | overflow: hidden;
93 | box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
94 | }
95 |
96 | .code-window-header {
97 | display: flex;
98 | align-items: center;
99 | padding: 0.5em 1em;
100 | background: #252526;
101 | border-bottom: 1px solid #333;
102 | }
103 |
104 | .window-button {
105 | width: 12px;
106 | height: 12px;
107 | border-radius: 50%;
108 | margin-right: 6px;
109 | }
110 |
111 | .window-button.red {
112 | background: #ff5f56;
113 | }
114 |
115 | .window-button.yellow {
116 | background: #ffbd2e;
117 | }
118 |
119 | .window-button.green {
120 | background: #27c93f;
121 | }
122 |
123 | .window-title {
124 | margin-left: 8px;
125 | font-size: 12px;
126 | color: #999;
127 | }
128 |
129 | /* Scrollbar styling */
130 | pre[class*="language-soplang"]::-webkit-scrollbar {
131 | width: 14px;
132 | height: 14px;
133 | }
134 |
135 | pre[class*="language-soplang"]::-webkit-scrollbar-track {
136 | background: #1e1e1e;
137 | }
138 |
139 | pre[class*="language-soplang"]::-webkit-scrollbar-thumb {
140 | background: #3e3e3e;
141 | border-radius: 10px;
142 | border: 3px solid #1e1e1e;
143 | }
144 |
145 | pre[class*="language-soplang"]::-webkit-scrollbar-thumb:hover {
146 | background: #505050;
147 | }
148 |
149 | /* Dark mode adjustments */
150 | .dark pre[class*="language-soplang"] {
151 | background: #121212;
152 | }
153 |
154 | .dark .code-window {
155 | background: #121212;
156 | }
157 |
158 | .dark .code-window-header {
159 | background: #1a1a1a;
160 | }
161 |
162 | .dark pre[class*="language-soplang"]::-webkit-scrollbar-track {
163 | background: #121212;
164 | }
165 |
166 | .dark pre[class*="language-soplang"]::-webkit-scrollbar-thumb {
167 | border-color: #121212;
168 | }
--------------------------------------------------------------------------------
/public/sitemap.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 | https://soplang.org
7 | daily
8 | 1.0
9 |
10 |
11 |
12 |
13 |
14 |
15 | https://soplang.org/downloads
16 | weekly
17 | 0.9
18 |
19 |
20 | https://soplang.org/docs
21 | weekly
22 | 0.9
23 |
24 |
25 | https://soplang.org/community
26 | weekly
27 | 0.8
28 |
29 |
30 | https://soplang.org/blog
31 | weekly
32 | 0.8
33 |
34 |
35 | https://soplang.org/about
36 | monthly
37 | 0.7
38 |
39 |
40 | https://soplang.org/about/help
41 | monthly
42 | 0.7
43 |
44 |
45 | https://soplang.org/contribute
46 | monthly
47 | 0.7
48 |
49 |
50 |
51 |
52 | https://soplang.org/downloads/latest
53 | weekly
54 | 0.8
55 |
56 |
57 | https://soplang.org/downloads/windows
58 | weekly
59 | 0.7
60 |
61 |
62 | https://soplang.org/downloads/macos
63 | weekly
64 | 0.7
65 |
66 |
67 | https://soplang.org/downloads/linux
68 | weekly
69 | 0.7
70 |
71 |
72 | https://soplang.org/downloads/source
73 | weekly
74 | 0.7
75 |
76 |
77 |
78 |
79 | https://soplang.org/docs/getting-started
80 | weekly
81 | 0.9
82 |
83 |
84 | https://soplang.org/docs/tutorial
85 | weekly
86 | 0.8
87 |
88 |
89 | https://soplang.org/docs/faq
90 | weekly
91 | 0.7
92 |
93 |
94 |
95 |
96 | https://soplang.org/blog/Soplang-2.0-Is-Almost-Here-A-Somali-first-Programming-Language-Nears-Major-Release
97 | monthly
98 | 0.8
99 |
100 |
101 |
102 |
103 | https://soplang.org/privacy
104 | monthly
105 | 0.3
106 |
107 |
108 | https://soplang.org/terms
109 | monthly
110 | 0.3
111 |
112 |
113 | https://soplang.org/trademarks
114 | monthly
115 | 0.3
116 |
117 |
118 |
119 |
120 | https://soplang.org/sitemap
121 | monthly
122 | 0.3
123 |
124 |
--------------------------------------------------------------------------------
/examples/43_random_function.sop:
--------------------------------------------------------------------------------
1 | // Test: Random Function (xul)
2 | // This test demonstrates the xul() function for generating random values
3 |
4 | qor("Testing random function (xul):")
5 |
6 | // Case 1: No arguments - random float between 0.0 and 1.0
7 | qor("\nGenerate random float between 0.0 and 1.0:")
8 | door randomFloat1 = xul()
9 | door randomFloat2 = xul()
10 | door randomFloat3 = xul()
11 | qor(" Random float 1: " + randomFloat1)
12 | qor(" Random float 2: " + randomFloat2)
13 | qor(" Random float 3: " + randomFloat3)
14 | qor(" Note: Values will be different on each run")
15 |
16 | // Case 2: Two number arguments - random number between a and b (inclusive)
17 | qor("\nGenerate random integers between ranges:")
18 | // Dice roll (1-6)
19 | door diceRoll1 = xul(1, 6)
20 | door diceRoll2 = xul(1, 6)
21 | door diceRoll3 = xul(1, 6)
22 | qor(" Dice roll 1 (1-6): " + diceRoll1)
23 | qor(" Dice roll 2 (1-6): " + diceRoll2)
24 | qor(" Dice roll 3 (1-6): " + diceRoll3)
25 |
26 | // Random number between 10 and 20
27 | door randomNum = xul(10, 20)
28 | qor(" Random number (10-20): " + randomNum)
29 |
30 | // Random decimal between ranges
31 | door randomDecimal = xul(0.5, 9.5)
32 | qor(" Random decimal (0.5-9.5): " + randomDecimal)
33 |
34 | // Case 3: One list argument - random item from list
35 | qor("\nSelect random items from lists:")
36 | // Names
37 | teed names = ["Ayaan", "Cali", "Zahra", "Ahmed", "Fadumo"]
38 | door randomName1 = xul(names)
39 | door randomName2 = xul(names)
40 | door randomName3 = xul(names)
41 | qor(" Random name 1: " + randomName1)
42 | qor(" Random name 2: " + randomName2)
43 | qor(" Random name 3: " + randomName3)
44 |
45 | // Mixed types
46 | teed mixedList = [42, "Soplang", been, [1, 2, 3], {name: "test"}]
47 | door randomItem = xul(mixedList)
48 | qor(" Random item from mixed list: " + randomItem)
49 |
50 | // Practical applications
51 | qor("\nPractical applications:")
52 |
53 | // 1. Random color generator
54 | teed colors = ["red", "green", "blue", "yellow", "purple", "orange"]
55 | door randomColor = xul(colors)
56 | qor(" Random color: " + randomColor)
57 |
58 | // 2. Random yes/no decision
59 | door randomValue = xul()
60 | door decision = ""
61 | haddii (randomValue > 0.5) {
62 | decision = "Haa"
63 | } ugudambeyn {
64 | decision = "Maya"
65 | }
66 | qor(" Random decision: " + decision)
67 |
68 | // 3. Password generator helper
69 | hawl randomChar() {
70 | teed chars = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M",
71 | "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z",
72 | "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m",
73 | "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z",
74 | "0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
75 | "!", "@", "#", "$", "%", "&", "*"]
76 | celi xul(chars)
77 | }
78 |
79 | qoraal password = ""
80 | kuceli (i 0 ilaa 7) {
81 | password = password + randomChar()
82 | }
83 | qor(" Random password: " + password)
84 |
85 | // 4. Simple dice game
86 | abn player1 = xul(1, 6)
87 | abn player2 = xul(1, 6)
88 | qor(" Dice game: Player 1 rolled " + player1 + ", Player 2 rolled " + player2)
89 |
90 | haddii (player1 > player2) {
91 | qor(" Player 1 wins!")
92 | } haddii_kale (player2 > player1) {
93 | qor(" Player 2 wins!")
94 | } ugudambeyn {
95 | qor(" It's a tie!")
96 | }
97 |
98 | qor("\nTesting error cases:")
99 | qor(" Note: The following lines would cause errors if uncommented:")
100 | qor(" // xul(1, 2, 3) // Too many arguments")
101 | qor(" // xul({}) // Not a list")
102 | qor(" // xul(6, 1) // First value greater than second")
103 | qor(" // xul([]) // Empty list")
104 |
105 |
106 | qor("\nRandom function tests completed!")
107 |
--------------------------------------------------------------------------------
/src/app/docs/objects/page.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import CodeWindow from "@/components/CodeWindow";
3 | import DocNavigation from "@/components/DocNavigation";
4 |
5 | export const metadata = {
6 | title: "Objects in Soplang",
7 | description:
8 | "Learn how to declare, modify, and manage walax (objects) in Soplang with Somali-first methods.",
9 | };
10 |
11 | export default function ObjectsPage() {
12 | return (
13 |
14 |
Objects in Soplang
15 |
16 | Objects in Soplang are defined using the walax type. They store key–value pairs
17 | and provide Somali-first methods to inspect, modify, and copy structured data.
18 |
19 |
20 | {/* Declaring an Object */}
21 |
22 | 🧾 Declaring an Object – walax
23 |
31 |
32 |
33 | {/* Core Methods */}
34 |
35 | 🔧 Core Object Methods
36 |
37 | fure() – Get Keys
38 |
43 |
44 | qiime() – Get Values
45 |
50 |
51 | lamaane() – Get Key-Value Pairs
52 |
57 |
58 | leeyahay(x) – Has Key
59 |
65 |
66 | tir(x) – Delete Key
67 |
72 |
73 | kudar(obj) – Merge/Assign
74 |
82 |
83 | nuqul() – Copy
84 |
90 |
91 | nadiifi() – Clear All Properties
92 |
97 |
98 |
99 |
100 | Gunaanad: walax waxay siisaa qaab awood badan oo lagu kaydiyo
101 | xog magacyo leh, iyadoo leh habab si buuxda ugu qoran Af-Soomaali.
102 |
103 |
104 |
117 |
118 | );
119 | }
120 |
--------------------------------------------------------------------------------
/src/app/sitemap/page.tsx:
--------------------------------------------------------------------------------
1 | import { Metadata } from "next";
2 | import Link from "next/link";
3 |
4 | export const metadata: Metadata = {
5 | title: "Sitemap - Soplang",
6 | description: "Complete sitemap of Soplang programming language website.",
7 | };
8 |
9 | const siteStructure = [
10 | {
11 | title: "Getting Started",
12 | links: [
13 | { name: "Introduction", href: "/docs/getting-started" },
14 | { name: "Quick Start Guide", href: "/docs/quick-start" },
15 | { name: "Installation", href: "/docs/installation" },
16 | { name: "First Program", href: "/docs/first-program" },
17 | ],
18 | },
19 | {
20 | title: "Downloads",
21 | links: [
22 | { name: "Latest Version", href: "/downloads/latest" },
23 | { name: "All Releases", href: "/downloads" },
24 | { name: "Windows", href: "/downloads/windows" },
25 | { name: "macOS", href: "/downloads/macos" },
26 | { name: "Linux", href: "/downloads/linux" },
27 | { name: "Source Code", href: "/downloads/source" },
28 | ],
29 | },
30 | {
31 | title: "Documentation",
32 | links: [
33 | { name: "Language Reference", href: "/docs/language" },
34 | { name: "Standard Library", href: "/docs/stdlib" },
35 | { name: "API Reference", href: "/docs/api" },
36 | { name: "Best Practices", href: "/docs/best-practices" },
37 | { name: "Examples", href: "/docs/examples" },
38 | { name: "Tutorials", href: "/docs/tutorials" },
39 | { name: "FAQs", href: "/docs/faq" },
40 | { name: "Extending Soplang", href: "/docs/extending" },
41 | ],
42 | },
43 | {
44 | title: "Community",
45 | links: [
46 | { name: "Community Home", href: "/community" },
47 | { name: "Discord", href: "https://discord.gg/n296G4dd7x" },
48 | { name: "GitHub", href: "https://github.com/soplang" },
49 | {
50 | name: "Discussions",
51 | href: "https://github.com/orgs/soplang/discussions",
52 | },
53 | { name: "Contributing", href: "/contribute" },
54 | ],
55 | },
56 | {
57 | title: "Blog",
58 | links: [
59 | { name: "Blog Home", href: "/blog" },
60 | {
61 | name: "Soplang 2.0",
62 | href: "/blog/Soplang-2.0-Is-Almost-Here-A-Somali-first-Programming-Language-Nears-Major-Release",
63 | },
64 | ],
65 | },
66 | {
67 | title: "About",
68 | links: [
69 | { name: "About Soplang", href: "/about" },
70 | { name: "Help", href: "/about/help" },
71 | ],
72 | },
73 | {
74 | title: "Legal",
75 | links: [
76 | { name: "Privacy Policy", href: "/privacy" },
77 | { name: "Terms of Use", href: "/terms" },
78 | { name: "Trademarks", href: "/trademarks" },
79 | ],
80 | },
81 | ];
82 |
83 | export default function SitemapPage() {
84 | return (
85 |
86 |
87 |
88 | Sitemap
89 |
90 |
91 |
92 | {siteStructure.map((section) => (
93 |
94 |
95 | {section.title}
96 |
97 |
98 | {section.links.map((link) => (
99 |
100 |
104 | {link.name}
105 |
106 |
107 | ))}
108 |
109 |
110 | ))}
111 |
112 |
113 |
114 |
115 | Can't find what you're looking for?{" "}
116 |
117 | Contact us
118 |
119 |
120 |
121 |
122 |
123 | );
124 | }
125 |
--------------------------------------------------------------------------------