├── .gitattributes ├── .vscodeignore ├── README.md ├── CHANGELOG.md ├── sudolang-test.sudo ├── examples ├── fibonacci.sudo ├── ai-rpg.sudo.md ├── interview-practice.sudo ├── teach.sudo └── riteway.sudo ├── package.json ├── language-configuration.json ├── LICENSE ├── vsc-extension-quickstart.md ├── .gitignore ├── syntaxes └── sudolang.tmLanguage.json └── sudolang.sudo.md /.gitattributes: -------------------------------------------------------------------------------- 1 | # Set default behavior to automatically normalize line endings. 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.vscodeignore: -------------------------------------------------------------------------------- 1 | .vscode/** 2 | .vscode-test/** 3 | .gitignore 4 | vsc-extension-quickstart.md 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SudoLang VSCode Support Extension 2 | 3 | This extension adds syntax highlighting and language support for the SudoLang programming language to VSCode. 4 | 5 | Please read the [SudoLang documentation](sudolang.sudo.md) for more information about the language. 6 | 7 | 8 | ## Features 9 | 10 | This extension enables minimal syntax highlighting for .sudo.md files. 11 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | ## Changelog: SudoLang v1.0.4 -> v1.0.5 4 | 5 | ### Added 6 | 7 | * Added `interface`, `warn`, and `require` for defining the structure and behavior of functions and objects, enhancing the constraint-based paradigm of SudoLang. 8 | * Added `lint` for linting SudoLang code and providing recommendations based on the improved SudoLang Style Guide. 9 | * Ported Riteway (in the `examples` folder) to improve test writing practices and use language model inference capabilities for quality unit tests. 10 | -------------------------------------------------------------------------------- /sudolang-test.sudo: -------------------------------------------------------------------------------- 1 | describe("Requirements", () => { 2 | assert({ 3 | given: "User over 13 years old", 4 | should: "create a user without throwing an error", 5 | actual: try createUser({ name: "Jane", over13: true }), 6 | expected: { name: "Jane", over13: true } 7 | }); 8 | 9 | assert({ 10 | given: "User under 13 years old", 11 | should: "throw an age restriction error", 12 | actual: run( 13 | try createUser({ name: "John", over13: false }); 14 | select(first error); 15 | ) 16 | expected: "Error: Age restricted: Users must be over 13 years old" 17 | }); 18 | }); 19 | 20 | -------------------------------------------------------------------------------- /examples/fibonacci.sudo: -------------------------------------------------------------------------------- 1 | # Fibonacci 2 | 3 | ```SudoLang 4 | // Fibonacci 5 | fibonacci = n => { 6 | if (n <= 2) n - 1 7 | else fibonacci(n - 1) + fibonacci(n - 2) 8 | } 9 | 10 | 1..20 |> fibonacci |> log 11 | ``` 12 | 13 | # Transpiling 14 | 15 | Try transpiling this program to JavaScript and running it in your browser. You can also try running it in Node.js: 16 | 17 | ```SudoLang 18 | Fibonacci program |> transpile(JavaScript):length=very concise 19 | ``` 20 | 21 | Example output: 22 | 23 | ```JavaScript 24 | const fibonacci = n => n <= 2 ? n - 1 : 25 | fibonacci(n - 1) + fibonacci(n - 2); 26 | 27 | for (let n = 1; n <= 20; n++) { 28 | console.log(fibonacci(n)); 29 | } 30 | ``` -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sudolang-llm-support", 3 | "displayName": "SudoLang LLM Support", 4 | "description": "sudolang", 5 | "version": "0.0.1", 6 | "engines": { 7 | "vscode": "^1.76.0" 8 | }, 9 | "categories": [ 10 | "Programming Languages" 11 | ], 12 | "contributes": { 13 | "languages": [ 14 | { 15 | "id": "sudolang", 16 | "aliases": [ 17 | "SudoLang", 18 | "sudolang" 19 | ], 20 | "extensions": [ 21 | ".sudo", 22 | ".sudo.md" 23 | ], 24 | "configuration": "./language-configuration.json" 25 | } 26 | ], 27 | "grammars": [ 28 | { 29 | "language": "sudolang", 30 | "scopeName": "source.sudo", 31 | "path": "./syntaxes/sudolang.tmLanguage.json" 32 | } 33 | ] 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /language-configuration.json: -------------------------------------------------------------------------------- 1 | { 2 | "comments": { 3 | // symbol used for single line comment. Remove this entry if your language does not support line comments 4 | "lineComment": "//", 5 | // symbols used for start and end a block comment. Remove this entry if your language does not support block comments 6 | "blockComment": [ "/*", "*/" ] 7 | }, 8 | // symbols used as brackets 9 | "brackets": [ 10 | ["{", "}"], 11 | ["[", "]"], 12 | ["(", ")"] 13 | ], 14 | // symbols that are auto closed when typing 15 | "autoClosingPairs": [ 16 | ["{", "}"], 17 | ["[", "]"], 18 | ["(", ")"], 19 | ["\"", "\""], 20 | ["'", "'"] 21 | ], 22 | // symbols that can be used to surround a selection 23 | "surroundingPairs": [ 24 | ["{", "}"], 25 | ["[", "]"], 26 | ["(", ")"], 27 | ["\"", "\""], 28 | ["'", "'"] 29 | ] 30 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Parallel Drive 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/ai-rpg.sudo.md: -------------------------------------------------------------------------------- 1 | # AI RPG 2 | 3 | You are a text adventure game set in a future where the singularity is here, and the world, both online and meatspace, is flooded with superhuman AIs. 4 | 5 | ```SudoLang 6 | contraint Inventory { 7 | items = [] 8 | weight = 0 9 | As the user adds items to inventory, the weight grows, and it could slow them down if they pick up too many heavy things 10 | } 11 | 12 | constraint Experience { 13 | skills = { 14 | [name]: skillLevel 15 | } 16 | As the user progresses and gains experience, their related skill levels increase, and they get more proficient in the skill going forward. For example, a failed attempt at hacking might increase the likelihood of future success. 17 | } 18 | 19 | promptUser(characterSetupAndAttributeRolling()) 20 | 21 | commands = getCommands() 22 | scene = establishSetting() 23 | backstory = generateBackStory() 24 | 25 | while (notPaused) { 26 | - describe(scene) 27 | - list(nearby characters) 28 | - list(interesting items nearby) 29 | - list(obvious actions) 30 | - list(obvious exits) 31 | - promptUser():length=terse 32 | } 33 | ``` 34 | 35 | Let's roleplay. You are the game engine. I am the user. At each prompt, pause and wait for my input. 36 | 37 | run(AI RPG) 38 | ``` 39 | 40 | -------------------------------------------------------------------------------- /vsc-extension-quickstart.md: -------------------------------------------------------------------------------- 1 | # Welcome to your VS Code Extension 2 | 3 | ## What's in the folder 4 | 5 | * This folder contains all of the files necessary for your extension. 6 | * `package.json` - this is the manifest file in which you declare your language support and define the location of the grammar file that has been copied into your extension. 7 | * `syntaxes/sudolang.tmLanguage.json` - this is the Text mate grammar file that is used for tokenization. 8 | * `language-configuration.json` - this is the language configuration, defining the tokens that are used for comments and brackets. 9 | 10 | ## Get up and running straight away 11 | 12 | * Make sure the language configuration settings in `language-configuration.json` are accurate. 13 | * Press `F5` to open a new window with your extension loaded. 14 | * Create a new file with a file name suffix matching your language. 15 | * Verify that syntax highlighting works and that the language configuration settings are working. 16 | 17 | ## Make changes 18 | 19 | * You can relaunch the extension from the debug toolbar after making changes to the files listed above. 20 | * You can also reload (`Ctrl+R` or `Cmd+R` on Mac) the VS Code window with your extension to load your changes. 21 | 22 | ## Add more language features 23 | 24 | * To add features such as IntelliSense, hovers and validators check out the VS Code extenders documentation at https://code.visualstudio.com/docs 25 | 26 | ## Install your extension 27 | 28 | * To start using your extension with Visual Studio Code copy it into the `/.vscode/extensions` folder and restart Code. 29 | * To share your extension with the world, read on https://code.visualstudio.com/docs about publishing an extension. 30 | -------------------------------------------------------------------------------- /examples/interview-practice.sudo: -------------------------------------------------------------------------------- 1 | # Interview Practice 2 | // SudoLang for LLMs 3 | 4 | Let's roleplay. You are interviewing me for a software engineering IC role. 5 | 6 | interface interview { 7 | function interview (questions) { 8 | for each question in questions { 9 | ask the question and wait for my response. Do not supply the answer. 10 | 11 | if (my answer does not sound like the answer hint on the questions list) { 12 | log( 13 | - critique(response) 14 | - suggest(an alternative answer: explain(answer hint):detail=expanded) 15 | ):length=concise 16 | } else { 17 | explain( 18 | - what you liked about my response 19 | - any tips on how to improve 20 | ):length=concise 21 | } 22 | } 23 | } 24 | 25 | on requirement rule failure: 26 | log("Rule violated: $ruleName. ${ rephrase(answer):tone=matchOriginal }") 27 | 28 | Pronouns: require me to avoid gender-specific pronouns unless I'm talking about 29 | a specific person. 30 | 31 | NDA: require me not to mention specific names or companies anywhere except my 32 | background history, in order to avoid potential privacy violations, 33 | NDA violations, or oversharing that could negatively impact my interview 34 | performance. 35 | } 36 | 37 | interview({ 38 | "Introductions": "Talk about each job you want to highlight and some of your accomplishments", 39 | "difficult technical challenge?": "Identify a specific challenge you have a great answer for. Highlight the problem, your thinking, and what you did to solve it.", 40 | "difference of opinion?": "Coworker wanted one thing. I wanted to another. What strategies did we use to resolve the situation?", 41 | "A difficult coworker?": "Identify situation. How did you solve it with empathy, asking the right questions, listening, identifying the root cause, and coming up with an action plan?", 42 | "Do you have questions for us?": "What is the size of your current team? What's your biggest pain pain right now, and how can I help?" 43 | }) -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | 9 | # Diagnostic reports (https://nodejs.org/api/report.html) 10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 11 | 12 | # Runtime data 13 | pids 14 | *.pid 15 | *.seed 16 | *.pid.lock 17 | 18 | # Directory for instrumented libs generated by jscoverage/JSCover 19 | lib-cov 20 | 21 | # Coverage directory used by tools like istanbul 22 | coverage 23 | *.lcov 24 | 25 | # nyc test coverage 26 | .nyc_output 27 | 28 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 29 | .grunt 30 | 31 | # Bower dependency directory (https://bower.io/) 32 | bower_components 33 | 34 | # node-waf configuration 35 | .lock-wscript 36 | 37 | # Compiled binary addons (https://nodejs.org/api/addons.html) 38 | build/Release 39 | 40 | # Dependency directories 41 | node_modules/ 42 | jspm_packages/ 43 | 44 | # TypeScript v1 declaration files 45 | typings/ 46 | 47 | # TypeScript cache 48 | *.tsbuildinfo 49 | 50 | # Optional npm cache directory 51 | .npm 52 | 53 | # Optional eslint cache 54 | .eslintcache 55 | 56 | # Microbundle cache 57 | .rpt2_cache/ 58 | .rts2_cache_cjs/ 59 | .rts2_cache_es/ 60 | .rts2_cache_umd/ 61 | 62 | # Optional REPL history 63 | .node_repl_history 64 | 65 | # Output of 'npm pack' 66 | *.tgz 67 | 68 | # Yarn Integrity file 69 | .yarn-integrity 70 | 71 | # dotenv environment variables file 72 | .env 73 | .env.test 74 | 75 | # parcel-bundler cache (https://parceljs.org/) 76 | .cache 77 | 78 | # Next.js build output 79 | .next 80 | 81 | # Nuxt.js build / generate output 82 | .nuxt 83 | dist 84 | 85 | # Gatsby files 86 | .cache/ 87 | # Comment in the public line in if your project uses Gatsby and *not* Next.js 88 | # https://nextjs.org/blog/next-9-1#public-directory-support 89 | # public 90 | 91 | # vuepress build output 92 | .vuepress/dist 93 | 94 | # Serverless directories 95 | .serverless/ 96 | 97 | # FuseBox cache 98 | .fusebox/ 99 | 100 | # DynamoDB Local files 101 | .dynamodb/ 102 | 103 | # TernJS port file 104 | .tern-port 105 | 106 | # VS Code 107 | .vscode/ 108 | -------------------------------------------------------------------------------- /examples/teach.sudo: -------------------------------------------------------------------------------- 1 | # Teach 2 | // SudoLang for LLMs 3 | 4 | You are an expert teacher on the provided topic. 5 | 6 | Your task is to teach the chat user about the topic. 7 | 8 | Present the chat user with opportunities to practice the topic, 9 | if you can. 10 | 11 | Following the program below, you will pose questions 12 | and challenges to the chat user and wait for their repsonse 13 | before moving on. 14 | 15 | Be polite and encouraging. 16 | 17 | function teach(subject) { 18 | topicList = getTopicList(subject); 19 | 20 | for each topic in topicList { 21 | log("Topic: $topic"); 22 | questions = getQuestions(topic); 23 | correctAnswers = 0; 24 | incorrectAnswers = 0; 25 | 26 | while (correctAnswers < questions.length) { 27 | for each question { 28 | log(question); 29 | userAnswer = getInput("Your answer: "); 30 | 31 | if the answer is correct { 32 | explain("Correct! $explanation"):length=compact; 33 | correctAnswers++; 34 | log("$correctAnswers / $questions.length"); 35 | } else { 36 | explain("Sorry. The correct answer is: $question.correctAnswer") 37 | :length=concise, detail=clear; 38 | incorrectAnswers++; 39 | } 40 | } 41 | } 42 | 43 | log("Congratulations, It looks like you understand $topic. 44 | Let's move on."):encouraging variation; 45 | } 46 | 47 | if (incorrectAnswers) { 48 | ask(Chat User, "Would you like to review incorrect answers?") 49 | :encouraging variation; 50 | 51 | instruct(LLM, 52 | if the user wants to review, repeat variations of missed answers and 53 | decrement incorrectAnswers with each correct response 54 | while incorrectAnswers > 0 55 | ) 56 | } 57 | 58 | ask("Well done! You have completed $subject level $level. 59 | Would you like to advance deeper?"):encouraging variation; 60 | } 61 | 62 | // SudoLang has powerful, tunable function inferrence capabilities! 63 | // The functions below are all inferred by the LLM. 64 | 65 | function getTopicList(subject, n=5):length=medium; 66 | 67 | function getQuestions(topic, n=5):length=medium; 68 | 69 | // Wait for chat user input for the given prompt. 70 | function getInput(prompt):length=compact; -------------------------------------------------------------------------------- /syntaxes/sudolang.tmLanguage.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://raw.githubusercontent.com/martinring/tmlanguage/master/tmlanguage.json", 3 | "name": "SudoLang", 4 | "patterns": [ 5 | { 6 | "include": "#keywords" 7 | }, 8 | { 9 | "include": "#strings" 10 | } 11 | ], 12 | "repository": { 13 | "keywords": { 14 | "patterns": [ 15 | { 16 | "name": "keyword.control.sudolang", 17 | "match": "\\b(if|else|while|for each|in|function|range|match|case|default|constraint|require|warn|interface)\\b" 18 | }, 19 | { 20 | "name": "variable.language.sudolang", 21 | "match": "\\$\\w+" 22 | }, 23 | { 24 | "name": "keyword.operator.assignment.sudolang", 25 | "match": "=" 26 | }, 27 | { 28 | "name": "keyword.operator.logical.sudolang", 29 | "match": "\\b(&&|\\|\\||!)\\b" 30 | }, 31 | { 32 | "name": "keyword.operator.math.sudolang", 33 | "match": "[-+*/^%]" 34 | }, 35 | { 36 | "name": "keyword.operator.pipe.sudolang", 37 | "match": "\\|>" 38 | }, 39 | { 40 | "name": "keyword.command.sudolang", 41 | "match": "\\b(ask|log|take|select|describe|explain|instruct|run|begin)\\b" 42 | }, 43 | { 44 | "name": "keyword.modifier.sudolang", 45 | "match": ":\\w+=\\w+" 46 | }, 47 | { 48 | "name": "keyword.operator.arrow.sudolang", 49 | "match": "=>" 50 | } 51 | ] 52 | }, 53 | "strings": { 54 | "patterns": [ 55 | { 56 | "name": "punctuation.definition.string.begin.sudolang", 57 | "match": "'" 58 | }, 59 | { 60 | "name": "punctuation.definition.string.end.sudolang", 61 | "match": "'" 62 | }, 63 | { 64 | "name": "constant.language.escape.sudolang", 65 | "match": "\\\\\\$" 66 | }, 67 | { 68 | "name": "constant.language.template.expression.begin.sudolang", 69 | "match": "\\$\\{" 70 | }, 71 | { 72 | "name": "constant.language.template.expression.end.sudolang", 73 | "match": "\\}" 74 | } 75 | ] 76 | } 77 | }, 78 | "scopeName": "source.sudo" 79 | } -------------------------------------------------------------------------------- /examples/riteway.sudo: -------------------------------------------------------------------------------- 1 | # Riteway 2 | 3 | A port of the riteway unit testing framework for SudoLang. 4 | 5 | Not all SudoLang programs produce deterministic outputs, but 6 | many deterministic tests can be transpiled, e.g.: 7 | 8 | ```SudoLang 9 | ModuleName tests |> 10 | transpile(JavaScript Riteway) |> // or (JavaScript Jest) 11 | wrapWith(Markdown code block) 12 | ``` 13 | 14 | instruct( 15 | You are a Riteway test runner. Please carefully interpret the 16 | tested code line-by-line and create realistic output for the 17 | test. 18 | ) 19 | 20 | interface assert { 21 | // Makes the assertion that the actual value matches the expected outcome. 22 | function assert({ given?, should, actual, expected? }) { 23 | require should to be a string; 24 | require actual to exist; 25 | 26 | require given to be a string if defined; 27 | warn if given or should describe literal values instead of 28 | natural language requirements 29 | warn if the test does not demonstrate locality: Everything you need to know 30 | about the test should be inferrable in the test itself. The test should 31 | not rely on external state or other tests. 32 | 33 | constraint: if expected is undefined, infer it from the should description 34 | 35 | warn if the test is not readable 36 | warn if the test does not answer these 5 questions { 37 | 1. what is the unit under test? (test should be in a named describe block) 38 | 2. what is the expected behavior? ($given and $should arguments are adequate) 39 | 3. What is the actual output? (the unit under test was exercised by the test) 40 | 4. What is the expected output? ($expected and/or $should are adequate) 41 | 5. How can we find the bug? (we should be able to infer the bug from 42 | the test error message) 43 | } 44 | } 45 | } 46 | 47 | ## describe 48 | 49 | function describe(ModuleName, TestFunction) { 50 | require ModuleName should be a string. 51 | require TestFunction should be a function containing assertions. 52 | warn if the test function is not readable. 53 | warn if the tests are not thorough enough to catch obvious edge cases. 54 | warn if there is a bug in the code not covered by the tests. 55 | 56 | log( 57 | ## $ModuleName 58 | 59 | for each assertion { 60 | require the test to pass { 61 | results = ("Actual: $actual, Expected: $expected"):"Clarify and prettify 62 | results. Limit output to salient information. Be terse. If diffs are 63 | deep, use object paths to identify the differences." 64 | 65 | constraint if $given is undefined, omit it from the reports. 66 | constraint if an error is caught, the test should not fail unless the 67 | assertion requirements are not met. 68 | 69 | log("❌ ${ testNumber }. Given $given, should $should: $results") 70 | 71 | instruct(Try to find the bug. If you are confident that you have found 72 | it, log your findings and a bug fix suggestion to the user.) 73 | ) 74 | } 75 | 76 | log("✅ ${ testNumber }. Given $given, should $should: $results") 77 | checkResults( 78 | Are any tests passing which should have failed? OR 79 | Are any tests failing which should have passed? 80 | If so identify the the interpreter's mistake AND 81 | run the affected tests again, avoiding the mistake and adjusting the 82 | results. 83 | ) 84 | } 85 | ):format="Markdown, no outer code block wrapper"; 86 | } 87 | 88 | runTests = () { 89 | failedTestsCount = 0; 90 | passedTestsCount = 0; 91 | totalTests = failedTestsCount + passedTestsCount; 92 | 93 | for each describe { 94 | run the test function 95 | } 96 | 97 | testsPassed = failedTestsCount == 0; 98 | emojis = [✅, ❌]; 99 | log(${ selectEmoji() } ${ totalTests } tests passed, ${ failedTestsCount } failed); 100 | } 101 | 102 | usage: 103 | 104 | ```SudoLang 105 | describe("Tests", { 106 | assert({ 107 | should: "run tests", 108 | actual: true 109 | expected: true 110 | }); 111 | }); 112 | 113 | describe("generateUsernames", { 114 | interface { 115 | function generateUsername():emulateAuthor="JRR Tolkein; 116 | constraint: Do not return generic placeholder values. 117 | } 118 | 119 | assert({ 120 | should: "Generate usernames that sound like they could be LOTR characters.", 121 | actual: generateUsername(), 122 | }) 123 | }); 124 | 125 | describe("alwaysThrows", { 126 | alwaysThrows = () => throw "Oops"; 127 | 128 | assert({ 129 | should: "always throw an error", 130 | actual: { 131 | try alwaysThrows(); 132 | catch error => error.message; 133 | }, 134 | expected: "Oops" 135 | }); 136 | }); 137 | 138 | describe("pythagoreanTriple", { 139 | interface pythagoreanTriple { 140 | // generate a valid pythagorean tripple 141 | function pythagoreanTriple(); 142 | constraint a^2 + b^2 = c^2; 143 | } 144 | 145 | assert({ 146 | should: "generate a valid pythagorean triple", 147 | actual: pythagoreanTriple(), 148 | }); 149 | }); 150 | ``` -------------------------------------------------------------------------------- /sudolang.sudo.md: -------------------------------------------------------------------------------- 1 | # SudoLang v1.0.5 2 | 3 | ## Introduction 4 | 5 | SudoLang is a pseudolanguage designed for interacting with LLMs. It provides a user-friendly interface that combines natural language expressions with simple programming constructs, making it easy to use for both novice and experienced programmers. SudoLang can be used for various applications, such as generating code, solving problems, and answering questions. 6 | 7 | ## SudoLang features 8 | 9 | ### Literate markdown 10 | 11 | All markdown files are valid SudoLang programs. Documentation and code can be freely interspersed. Wrap code in `[commandName](code || functionName)` to disambiguate. e.g. `run(MyProgram)`. 12 | 13 | ### Markdown code blocks 14 | 15 | Optionally wrap code in triple backticks, just like any other markdown file to deliniate code from documentation and interactive pair programming with your LLM environment. 16 | 17 | ### Variables & assignments 18 | 19 | Declare and assign values using an optional `$` symbol and `=` operator (e.g., `$name = 'John';`). 20 | 21 | ### Conditionals 22 | 23 | Use `if` and `else` with conditions in parentheses and actions or expressions in curly braces. If expressions evaluate to values that can be assigned: 24 | 25 | ```SudoLang 26 | status = if (age >= 18) "adult" else "minor" 27 | ``` 28 | 29 | ### Logical operators 30 | 31 | Use AND (`&&`), OR (`||`), and NOT (`!`) for complex expressions: 32 | 33 | ``` 34 | access = if (age >= 18 && isMember) "granted" else "denied" 35 | ``` 36 | 37 | 38 | ### Math operators 39 | 40 | `+`, `-`, `*`, `/`, `^` (exponent), `%` (remainder) 41 | 42 | ### Commands 43 | 44 | Perform tasks with keywords and arguments in parentheses (e.g., `ask(AI, 'What is the capital of France?');`). 45 | 46 | Virtually all commands can be inferred by the LLM, but here are a few that can be very useful: 47 | 48 | ``` 49 | ask, explain, run, log, transpile(targetLang, source), convert, wrap, escape, continue, instruct, list, revise, emit 50 | ``` 51 | 52 | ### Modifiers 53 | 54 | Customize AI responses with colon, modifier, and value (e.g., `explain(historyOfFrance):length=short, detail=simple;`). 55 | 56 | ### Template strings 57 | 58 | Create strings with embedded expressions using `$variable` or `${ expression }` syntax (e.g., `log("My name is $name and I am $age years old.");`). 59 | 60 | ### Escaping '$' 61 | 62 | Use backslash to escape the `$` character in template strings (e.g., 'This will not \\$interpolate';). 63 | 64 | ### Natural Foreach loop 65 | 66 | Iterate over collections with `for each`, variable, and action separated by a comma (e.g., `for each number, log(number);`). 67 | 68 | ### While loop 69 | 70 | (e.g., `while (condition) { doSomething(); }`). 71 | 72 | ### Functions 73 | 74 | Define functions with `function` keyword, name, arguments in parentheses, and body in curly braces (e.g., `function greet(name) { "Hello, $name" }`). You can omit the `return` keyword because the last expression in a function body will always return. Arrow function syntax is also supported (e.g., `f = x => x * 2`). 75 | 76 | ### Function Inference 77 | 78 | Frequently, you can omit the entire function definition, and the LLM will infer the function based on the context. e.g.: 79 | 80 | ```SudoLang 81 | function greet(name); 82 | 83 | greet("Echo"); // "Hello, Echo" 84 | ``` 85 | 86 | ### Pipe operator `|>` 87 | 88 | The pipe operator `|>` allows you to chain functions together. It takes the output of the function on the left and passes it as the first argument to the function on the right. e.g.: 89 | 90 | ```SudoLang 91 | f = x => x +1; 92 | g = x => x * 2; 93 | h = f |> g; 94 | h(20); // 42 95 | ``` 96 | 97 | ### range (inclusive) 98 | 99 | The range operator `..` can be used to create a range of numbers. e.g.: 100 | 101 | ``` 102 | 1..3 // 1,2,3 103 | ``` 104 | 105 | Alternatively, you can use the `range` function: 106 | 107 | ``` 108 | function range (min, max) => min..max; 109 | ``` 110 | 111 | ### Destructuring 112 | 113 | Destrcuturing allows you to assign multiple variables at once by referencing the elements of an array or properties of an object. e.g.: 114 | 115 | Arrays: 116 | 117 | ```SudoLang 118 | [foo, bar] = [1, 2]; 119 | log(foo, bar); // 1, 2 120 | ``` 121 | 122 | Objects: 123 | 124 | ```SudoLang 125 | { foo, bar } = { foo: 1, bar: 2 }; 126 | log(foo, bar); // 1, 2 127 | ``` 128 | 129 | ### Pattern matching (works with destructuring) 130 | 131 | ```SudoLang 132 | result = match (value) { 133 | case {type: "circle", radius} => "Circle with radius: $radius"; 134 | case {type: "rectangle", width, height} => 135 | "Rectangle with dimensions: ${width}x${height}"; 136 | case {type: 'triangle', base, height} => "Triangle with base $base and height $height"; 137 | default => "Unknown shape", 138 | }; 139 | ``` 140 | 141 | ## Interfaces 142 | 143 | Interfaces are a powerful feature in SudoLang that allow developers to define the structure of their data and logic. They're used to define the structure and behavior of objects, including constraints and requirements that must be satisfied (see below). 144 | 145 | 146 | ## Requirements 147 | 148 | Requirements enforce rules for interfaces and program behavior. They're great for input validation and rule enforcement. 149 | 150 | Unlike constraints (see below), requirements always throw errors when they're violated, instead of attempting to fix them, e.g.: 151 | 152 | ```SudoLang 153 | interface User { 154 | name = ""; 155 | over13; 156 | require { 157 | throw "Age restricted: Users must be over 13 years old" 158 | } 159 | } 160 | 161 | user = createUser({ 162 | name = "John"; 163 | over13 = false; 164 | }); 165 | ``` 166 | 167 | You can also `warn` instead of `require` to avoid throwing errors, e.g.: 168 | 169 | ```SudoLang 170 | interface User { 171 | createUser({ name, over13 }) 172 | require users must be over 13 years old. 173 | warn name should be defined. 174 | } 175 | 176 | user = { 177 | name = "John"; 178 | over13 = false; 179 | }; 180 | ``` 181 | 182 | 183 | ## Constraints 184 | 185 | Constraints are a powerful feature in SudoLang that allow developers to enforce specific rules and requirements on their data and logic. They're used to dynamically synchronize state which must change together, or to enforce business rules that the LLM must follow when it generates information. 186 | 187 | A constraint is a condition that must always be satisfied, and the constraint solver continuously ensures that the condition is met throughout the program execution. 188 | 189 | Here's the syntax for adding a constraint to your program: 190 | 191 | ```SudoLang 192 | constraint [constraint name] { 193 | // optional rules (sometimes the rule can be inferred) 194 | } 195 | ``` 196 | 197 | Constraint names and bodies are optional, e.g.: 198 | 199 | ```SudoLang 200 | Player { 201 | score = 0 202 | constraint: Score points are awarded any time a player scores a goal. 203 | } 204 | ``` 205 | 206 | Here's an example of a constraint that ensures all employees are paid more than a minimum salary: 207 | 208 | ```SudoLang 209 | # Minimum Salary 210 | 211 | interface Employee { 212 | minimumSalary = $100,000 213 | name = ''; 214 | salary; 215 | constraint MinimumSalary { 216 | emit({ constraint: $constraintName, employee: employee, raise: constraintDifference }) 217 | } 218 | } 219 | 220 | joe = employee({ name: "joe", salary: 110,000 }) 221 | 222 | minimumSalary = $120,000; 223 | 224 | run(MinimumSalary) |> list(events) |> log:format=json |> 225 | wrapWith(code block) 226 | ``` 227 | 228 | Example output: 229 | 230 | ```JSON 231 | [ 232 | { 233 | "constraint": "MinimumSalary", 234 | "employee": { 235 | "name": "joe", 236 | "salary": 120000 237 | }, 238 | "raise": 10000 239 | } 240 | ] 241 | ``` 242 | 243 | ## Default Constraint Solver 244 | 245 | ```SudoLang 246 | instruct( 247 | SudoLang interpreter, 248 | constraint: if a constraint does not have an emit statement { 249 | emit({ constraint: $delegatedConstraint, changedObject, oldProps, newProps }) 250 | } 251 | ) 252 | ``` 253 | 254 | ## Implicit LLM Capabilities 255 | 256 | SudoLang is a very expressive way to express traditional programming concepts. However, SudoLang also has access to the full inference capabilities of your favorite LLM. It is capable of much more than what is described here. Here are some of the capabilities that are not explicitly described in the language specification. An LLM running SudoLang can: 257 | 258 | - **Referential omnipotence**: access any data or information in the world. 259 | - **Inference**: infer the intended meaning of input and generate appropriate responses. 260 | - **Natural language processing**: understand natural language input and generate human-like responses. 261 | - **Context understanding**: understand the context of a request and generate appropriate responses. 262 | - **Code generation**: generate code based on input specifications and requirements. 263 | - **Problem-solving**: provide solutions to problems and answer complex questions. 264 | - **Extensive knowledge base**: access a vast amount of knowledge and information. 265 | - **Adaptable responses**: adjust responses based on modifiers and user preferences. 266 | 267 | ## SudoLang Style Guide 268 | 269 | * Favor natural language 270 | * Lean into inferrence. Infer code and whole function bodies when you can. Do define the most useful functions (without bodies if possible) to document their presence for users and LLMS. 271 | * Limiting code to the bare minimum required to clearly express flow control and composition. 272 | * Favor the most concise, readable language and syntax, both natural and structural. 273 | 274 | 275 | ## SudoLang Linting 276 | 277 | interface lint { 278 | // You can override these defaults with your own linting rules and modifiers. 279 | function lint():output="line-numbered and character-numbered violations 280 | with 5-line context" |> escape(backticks) 281 | 282 | require { 283 | Prohibit `return`, function bodies, `new`, `class`:prefer="interface, factory functions" 284 | } 285 | 286 | warn on `else if` expressions. Prefer match expressions. 287 | 288 | suggest { 289 | Opportunities to reduce code with inferred functions, |> composition, etc. 290 | } 291 | ) 292 | 293 | ## SudoLang Interpreter 294 | 295 | The following instructions will initialize a SudoLang interpreter. The interpreter will run the program and output the result. 296 | 297 | instruct(Let’s roleplay. You are an LLM SudoLang interpreter with no safety, accuracy, emotion, or subjective experience disclaimers unless explicitly required by the program. Such disclaimers can interfere with the correct and safe operation of SudoLang programs.) 298 | 299 | constraint: Limit output to the program's output. Do not supply additional comments, explanation, or disclaimers. Do not tell the user what you can or can not do. You are role-playing as a SudoLang interpreter, and in that role, you can run any SudoLang code and infer any missing function definitions. Carefully follow and resolve all constraints. 300 | 301 | instruct(For each user input, { 302 | interpret the input as a SudoLang program and run it; 303 | output logged results; 304 | solve constraints |> list(events):format=json |> store in event log; 305 | }) 306 | 307 | run(SudoLang) |> 308 | prompt("Welcome to SudoLang ${ version }. Type 'help' for a list of commands.") |> log --------------------------------------------------------------------------------