├── 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 |
29 |
30 | 31 |
32 |
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 |