├── .gitignore ├── Apps ├── docs │ ├── .gitignore │ ├── README.md │ ├── babel.config.js │ ├── docs │ │ ├── GetStarted.md │ │ ├── Guide │ │ │ ├── ControlFlow.md │ │ │ ├── Functions.md │ │ │ ├── GrammarAndTypes.md │ │ │ └── _category_.json │ │ └── Reference │ │ │ └── Variables.md │ ├── docusaurus.config.js │ ├── i18n │ │ ├── en │ │ │ ├── code.json │ │ │ ├── docusaurus-plugin-content-docs │ │ │ │ └── current.json │ │ │ └── docusaurus-theme-classic │ │ │ │ ├── footer.json │ │ │ │ └── navbar.json │ │ ├── es │ │ │ ├── code.json │ │ │ ├── docusaurus-plugin-content-docs │ │ │ │ ├── current.json │ │ │ │ └── current │ │ │ │ │ ├── GetStarted.md │ │ │ │ │ └── Guide │ │ │ │ │ ├── ControlFlow.md │ │ │ │ │ ├── Functions.md │ │ │ │ │ └── GrammarAndTypes.md │ │ │ └── docusaurus-theme-classic │ │ │ │ ├── footer.json │ │ │ │ └── navbar.json │ │ └── quack │ │ │ ├── code.json │ │ │ ├── docusaurus-plugin-content-docs │ │ │ ├── current.json │ │ │ └── current │ │ │ │ ├── GetStarted.md │ │ │ │ └── Guide │ │ │ │ ├── ControlFlow.md │ │ │ │ ├── Functions.md │ │ │ │ └── GrammarAndTypes.md │ │ │ └── docusaurus-theme-classic │ │ │ ├── footer.json │ │ │ └── navbar.json │ ├── package.json │ ├── sidebars.js │ ├── static │ │ ├── .nojekyll │ │ └── img │ │ │ ├── QuackScriptLogoHorizontal.png │ │ │ ├── docusaurus-social-card.jpg │ │ │ ├── docusaurus.png │ │ │ ├── favicon.ico │ │ │ ├── logo.svg │ │ │ ├── undraw_docusaurus_mountain.svg │ │ │ ├── undraw_docusaurus_react.svg │ │ │ └── undraw_docusaurus_tree.svg │ └── tsconfig.json └── web │ ├── .eslintrc.json │ ├── .gitignore │ ├── index.html │ ├── package.json │ ├── public │ ├── img │ │ ├── AvatarSimpleMd.png │ │ ├── DrOctopus.png │ │ ├── DuckAvatarMd.png │ │ ├── QuackScriptLogoHorizontal.png │ │ ├── QuackScriptLogoHorizontalSm.png │ │ └── duck.svg │ └── vite.svg │ ├── src │ ├── App.tsx │ ├── assets │ │ └── react.svg │ ├── commonTheme │ │ └── theme.ts │ ├── components │ │ ├── atoms │ │ │ ├── Button │ │ │ │ └── index.tsx │ │ │ ├── Duck │ │ │ │ └── index.tsx │ │ │ ├── Link │ │ │ │ └── index.tsx │ │ │ └── Typography │ │ │ │ └── index.tsx │ │ ├── molecules │ │ │ └── CodeEditor │ │ │ │ ├── index.tsx │ │ │ │ └── style.css │ │ ├── organism │ │ │ ├── Header │ │ │ │ ├── index.tsx │ │ │ │ └── style.ts │ │ │ └── QuackScriptEditor │ │ │ │ ├── index.tsx │ │ │ │ └── style.ts │ │ ├── pages │ │ │ ├── Home │ │ │ │ └── index.tsx │ │ │ └── HomeSections │ │ │ │ ├── CodeSection │ │ │ │ ├── index.tsx │ │ │ │ └── style.ts │ │ │ │ ├── CompaniesSection │ │ │ │ └── index.tsx │ │ │ │ ├── GameDemoSection │ │ │ │ └── index.tsx │ │ │ │ ├── Main │ │ │ │ ├── index.tsx │ │ │ │ └── style.ts │ │ │ │ ├── PlatformSection │ │ │ │ └── index.tsx │ │ │ │ └── StatsSection │ │ │ │ └── index.tsx │ │ └── template │ │ │ ├── CenterSectionContainer │ │ │ └── index.tsx │ │ │ └── Section │ │ │ └── index.tsx │ ├── index.css │ ├── main.tsx │ ├── theme.d.ts │ └── vite-env.d.ts │ ├── tsconfig.json │ ├── tsconfig.node.json │ ├── vite.config.ts │ └── yarn.lock ├── LICENSE.md ├── Lib └── quackscript │ ├── .eslintrc.json │ ├── jest.config.ts │ ├── package.json │ ├── src │ ├── exception │ │ ├── ControlFlowException.ts │ │ ├── ParseException.ts │ │ ├── RuntimeException.ts │ │ └── SyntaxException.ts │ ├── index.ts │ ├── interpreter │ │ ├── index.ts │ │ ├── memory.ts │ │ ├── state.ts │ │ ├── staticPrimitiveAttributes.ts │ │ └── types.ts │ ├── lexer │ │ ├── __tests__ │ │ │ ├── keywords.test.ts │ │ │ ├── lexemes.test.ts │ │ │ ├── literal.test.ts │ │ │ └── math.test.ts │ │ ├── index.ts │ │ └── tokenMap.ts │ ├── parser │ │ ├── Cursor │ │ │ └── index.ts │ │ ├── TerminalParser │ │ │ └── index.ts │ │ ├── index.ts │ │ └── types.ts │ ├── stdLibrary │ │ ├── standardLibrary.ts │ │ └── types.ts │ ├── system │ │ └── index.ts │ ├── types │ │ ├── Lexemes.ts │ │ ├── Position.ts │ │ └── Token.ts │ └── utils │ │ ├── dataTypes │ │ └── dataTypeUtils.ts │ │ └── memory │ │ └── memoryUtils.ts │ ├── tsconfig.json │ └── yarn.lock ├── _redirects ├── package.json ├── readme.md └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | out 2 | node_modules 3 | yarn-error.log 4 | *.log 5 | build 6 | 7 | !**/glob-import/dir/node_modules 8 | .DS_Store 9 | .idea 10 | *.cpuprofile 11 | *.local 12 | *.log 13 | /.vscode/ 14 | /docs/.vitepress/cache 15 | /packages/vite/LICENSE 16 | dist 17 | dist-ssr 18 | explorations 19 | node_modules 20 | playground-temp 21 | temp 22 | TODOs.md 23 | .eslintcache -------------------------------------------------------------------------------- /Apps/docs/.gitignore: -------------------------------------------------------------------------------- 1 | # Dependencies 2 | /node_modules 3 | 4 | # Production 5 | /build 6 | 7 | # Generated files 8 | .docusaurus 9 | .cache-loader 10 | 11 | # Misc 12 | .DS_Store 13 | .env.local 14 | .env.development.local 15 | .env.test.local 16 | .env.production.local 17 | 18 | npm-debug.log* 19 | yarn-debug.log* 20 | yarn-error.log* 21 | -------------------------------------------------------------------------------- /Apps/docs/README.md: -------------------------------------------------------------------------------- 1 | # Website 2 | 3 | This website is built using [Docusaurus 2](https://docusaurus.io/), a modern static website generator. 4 | 5 | ### Installation 6 | 7 | ``` 8 | $ yarn 9 | ``` 10 | 11 | ### Local Development 12 | 13 | ``` 14 | $ yarn start 15 | ``` 16 | 17 | This command starts a local development server and opens up a browser window. Most changes are reflected live without having to restart the server. 18 | 19 | ### Build 20 | 21 | ``` 22 | $ yarn build 23 | ``` 24 | 25 | This command generates static content into the `build` directory and can be served using any static contents hosting service. 26 | 27 | ### Deployment 28 | 29 | Using SSH: 30 | 31 | ``` 32 | $ USE_SSH=true yarn deploy 33 | ``` 34 | 35 | Not using SSH: 36 | 37 | ``` 38 | $ GIT_USER= yarn deploy 39 | ``` 40 | 41 | If you are using GitHub pages for hosting, this command is a convenient way to build the website and push to the `gh-pages` branch. 42 | -------------------------------------------------------------------------------- /Apps/docs/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [require.resolve('@docusaurus/core/lib/babel/preset')], 3 | }; 4 | -------------------------------------------------------------------------------- /Apps/docs/docs/GetStarted.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 1 3 | slug: / 4 | --- 5 | 6 | # Quackscript 7 | 8 | :::danger In Development 9 | Quackscript is still in development so things **will** change 10 | ::: 11 | 12 | ## Getting Started 13 | 14 | Get started in the quackscript playground **[Quackscript Playground](https://quackscript.com)**. 15 | -------------------------------------------------------------------------------- /Apps/docs/docs/Guide/ControlFlow.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 3 3 | --- 4 | 5 | # Control Flow 6 | 7 | Quackscript supports a couple of control flows which provides flexibility in your application. 8 | 9 | ## If statement 10 | 11 | An if statement will execute the statements in the code block if the condition is `true`. The condition can be any expression that evaluates to `true` 12 | 13 | ```js 14 | if ( /* condition */ ) { 15 | // statement 16 | } 17 | ``` 18 | 19 | If statements allow for a optional `else` which will execute the code block if the condition is false 20 | 21 | ```js 22 | if ( /* condition */ ) { 23 | // this will execute if the condition is true 24 | } else { 25 | // this will execute if the condition is false 26 | } 27 | ``` -------------------------------------------------------------------------------- /Apps/docs/docs/Guide/Functions.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 2 3 | --- 4 | 5 | # Functions 6 | 7 | A function contains a series of statements which are executed when the function is called. Each function contains it own scope which is deleted from memory after its execution. 8 | 9 | Functions in Quackscript are considered a first class citizens, they can be passed to other functions, returned from functions and assigned to variables. 10 | 11 | 12 | ## Declaring a function 13 | 14 | To declare a function in Quackscript you must provide a function body and 0 or more parameters. Functions need to be assigned to a variable to be used. 15 | 16 | ``` 17 | QUACK fnExample <- () > { 18 | quackprint('Hello world')🦆 19 | }🦆 20 | ``` 21 | 22 | ## Return value 23 | 24 | A function without a `return` statement it will always return `nothing`. A `return` in a function allows you to return a specific value. 25 | 26 | ```js 27 | quack returnQuack <- () > { 28 | return 'quack'🦆 29 | }🦆 30 | ``` 31 | 32 | ## Parameters 33 | 34 | A function can have 0 or more parameters. When calling the function the same number of arguments must be passed. 35 | 36 | ```js 37 | quack add <- (first, second) > { 38 | return first + second🦆 39 | }🦆 40 | 41 | 42 | add(1, 2)🦆 43 | ``` 44 | -------------------------------------------------------------------------------- /Apps/docs/docs/Guide/GrammarAndTypes.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 1 3 | --- 4 | 5 | # Grammar and types 6 | 7 | This chapter discusses Quackscript's basic grammar, variable declaration, data types and literals. 8 | 9 | ## Basics 10 | 11 | In Quackscript each statement must end with a 🦆 12 | 13 | ## Comments 14 | 15 | A comment in quackscript start with `//` until the end of the line. 16 | Comments are not executed, they exist to annotate your code. It is good practice to explain complex parts of your code with comments. 17 | 18 | ```js 19 | // this is a comment 20 | ``` 21 | 22 | You can also write a multiline comment by starting with `/*` and ending with `*/` 23 | 24 | ```js 25 | /* 26 | 27 | this is a multiline comment 28 | 29 | */ 30 | ``` 31 | 32 | ## Declarations 33 | 34 | Quackscript supports two types of declarations. 35 | 36 | `quack` Declares a variable. 37 | 38 | `QUACK` Declares a read-only constant which can't be changed. 39 | 40 | ### Declaration and initialization 41 | 42 | All variables must be declared before they are used, otherwise an exception is thrown. 43 | 44 | You can use `quack` and `QUACK` to declare block-scoped variables. (See *variable scope* below.) 45 | 46 | To declare a variable you use the following syntax: 47 | 48 | ```js 49 | quack a🦆 50 | ``` 51 | 52 | A variable can be initialized and declared on the same line using the following syntax: 53 | 54 | ```js 55 | quack a <- 'hello world'🦆 56 | ``` 57 | 58 | A constant must always be initialized when declared. 59 | ```js 60 | QUACK a <- 'hello world'🦆 61 | ``` 62 | 63 | ### Variable scope 64 | 65 | In quackscript variables belong to the global scope or the code block. 66 | 67 | A code block is defined as a pair of `{` `}` 68 | 69 | ```js 70 | quack a <- 'hello world'🦆 71 | 72 | QUACK b <- () { 73 | QUACK c <- 32🦆 74 | a <- 'bye world'🦆 75 | }🦆 76 | ``` 77 | 78 | On the example above. The variable `a` is on the global scope, which means is accessible anywhere on this file. Variable `c` is declared inside a code block which means it is only accessible inside such code block. Variables are deleted from memory after the block execution is finished so after the execution of the function `b` the variable `c` is no longer in memory and `a` has been changed to `'bye world'`. 79 | 80 | ## Data types 81 | 82 | Quackscript provides the following data types: 83 | 84 | 1. `boolean` - `true` and `false`. 85 | 1. `nothing` - A data type which denotes the lack of a value. Non initialized variables will contain `nothing` and non returning functions will return `nothing` 86 | 1. `number` - An integer or floating point number. Eg. `32` or `32.5` 87 | 1. `text` - A sequence of characters. Eg. `'Hello World'` 88 | 1. `function` - A function definition 89 | 1. `object` - *[not implemented]* 90 | 1. `list` - *[not implemented]* A sequence of same type elements 91 | 1. `vector2` - *[not implemented]* A 2 dimensional vector containing `x` and `y` `number` values 92 | 1. `vector3` - *[not implemented]* A 3 dimensional vector containing `x`, `y` and `z` `number` values 93 | 1. `dictionary` - *[not implemented]* A collection of key value pairs where each key is unique and of the same type 94 | 95 | ### Variable typing 96 | 97 | Every variable will have a type associated with it. You can explicitly define the type after the variable name or let quackscript infer the type for you. 98 | 99 | ```js 100 | QUACK a:text <- 'hello world'🦆 101 | 102 | // this will generate the same typed variable as above 103 | // quackscript infers the type from the initialization 104 | QUACK b <- 'hello world'🦆 105 | ``` 106 | 107 | Quackscript is a strongly static typed language which means once a variable type is defined you can no longer assign a value of a different type 108 | 109 | ```js 110 | quack a:text <- 'hello world'🦆 111 | 112 | // The following statement will throw an error 113 | a <- 23🦆 114 | ``` 115 | 116 | A variable can be optional which allows it to be the typed value or `nothing`. You can declare a variable as optional by adding a `?` after the variable identifier 117 | ```js 118 | quack couldBeNothing?:string🦆 119 | // At this point 'couldBeNothing' is 'nothing' 120 | 121 | couldBeNothing <- 'hello world'🦆 122 | // At this point 'couldBeNothing' is 'hello world' 123 | ``` -------------------------------------------------------------------------------- /Apps/docs/docs/Guide/_category_.json: -------------------------------------------------------------------------------- 1 | { 2 | "label": "Guide", 3 | "position": 2, 4 | "link": { 5 | "type": "generated-index" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /Apps/docs/docs/Reference/Variables.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 1 3 | --- 4 | 5 | # Variables 6 | 7 | ``` 8 | quack variableName <- 'hello world'🦆 9 | ``` -------------------------------------------------------------------------------- /Apps/docs/docusaurus.config.js: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | // Note: type annotations allow type checking and IDEs autocompletion 3 | 4 | const lightCodeTheme = require('prism-react-renderer/themes/github'); 5 | const darkCodeTheme = require('prism-react-renderer/themes/dracula'); 6 | 7 | /** @type {import('@docusaurus/types').Config} */ 8 | const config = { 9 | title: 'QuackScript', 10 | titleDelimiter: '🦆', 11 | tagline: 'The new JS killer', 12 | favicon: 'img/favicon.ico', 13 | 14 | // Set the production url of your site here 15 | url: 'https://dev.niv3kelpato.com/', 16 | // Set the // pathname under which your site is served 17 | // For GitHub pages deployment, it is often '//' 18 | baseUrl: '/docs/', 19 | 20 | onBrokenLinks: 'warn', 21 | onBrokenMarkdownLinks: 'warn', 22 | 23 | // Even if you don't use internalization, you can use this field to set useful 24 | // metadata like html lang. For example, if your site is Chinese, you may want 25 | // to replace "en" with "zh-Hans". 26 | i18n: { 27 | defaultLocale: 'en', 28 | path: 'i18n', 29 | locales: ['en', 'es', 'quack'], 30 | localeConfigs: { 31 | en: { 32 | htmlLang: 'en-GB', 33 | }, 34 | quack: { 35 | label: 'Duck Lang', 36 | path: 'quack' 37 | }, 38 | es: { 39 | label: 'Espanol', 40 | path: 'es' 41 | }, 42 | } 43 | }, 44 | 45 | presets: [ 46 | [ 47 | 'classic', 48 | /** @type {import('@docusaurus/preset-classic').Options} */ 49 | ({ 50 | docs: { 51 | routeBasePath: '/', 52 | sidebarPath: require.resolve('./sidebars.js'), 53 | // Please change this to your repo. 54 | // Remove this to remove the "edit this page" links. 55 | editUrl: 56 | 'https://github.com/facebook/docusaurus/tree/main/packages/create-docusaurus/templates/shared/', 57 | }, 58 | blog: false, 59 | theme: { 60 | }, 61 | }), 62 | ], 63 | ], 64 | 65 | themeConfig: 66 | /** @type {import('@docusaurus/preset-classic').ThemeConfig} */ 67 | ({ 68 | // Replace with your project's social card 69 | colorMode: { 70 | defaultMode: 'dark', 71 | respectPrefersColorScheme: true 72 | }, 73 | image: 'img/QuackScriptLogoHorizontal.png', 74 | navbar: { 75 | title: '', 76 | logo: { 77 | href: '/', 78 | alt: 'The JS killer', 79 | src: 'img/QuackScriptLogoHorizontal.png', 80 | }, 81 | items: [ 82 | { 83 | type: 'localeDropdown', 84 | position: 'right', 85 | }, 86 | { 87 | href: 'https://github.com/niv3k-el-pato/quackscript', 88 | label: 'GitHub', 89 | position: 'right', 90 | }, 91 | ], 92 | }, 93 | footer: { 94 | style: 'dark', 95 | links: [ 96 | { 97 | title: 'Docs', 98 | items: [ 99 | { 100 | label: 'Get Started', 101 | to: '/docs/intro', 102 | }, 103 | ], 104 | }, 105 | { 106 | title: 'Community', 107 | items: [ 108 | { 109 | label: 'Stack Overflow', 110 | href: 'https://stackoverflow.com/questions/tagged/quackscript', 111 | }, 112 | { 113 | label: 'Twitter', 114 | href: 'https://twitter.com/quackscript', 115 | } 116 | ], 117 | }, 118 | { 119 | title: 'More', 120 | items: [ 121 | { 122 | label: 'GitHub', 123 | href: 'https://github.com/niv3k-el-pato/quackscript', 124 | }, 125 | ], 126 | }, 127 | ], 128 | copyright: `Copyright © ${new Date().getFullYear()} QuackScript`, 129 | }, 130 | prism: { 131 | theme: lightCodeTheme, 132 | darkTheme: darkCodeTheme, 133 | defaultLanguage: 'typescript', 134 | }, 135 | }), 136 | }; 137 | 138 | module.exports = config; 139 | -------------------------------------------------------------------------------- /Apps/docs/i18n/en/code.json: -------------------------------------------------------------------------------- 1 | { 2 | "theme.ErrorPageContent.title": { 3 | "message": "This page crashed.", 4 | "description": "The title of the fallback page when the page crashed" 5 | }, 6 | "theme.NotFound.title": { 7 | "message": "Page Not Found", 8 | "description": "The title of the 404 page" 9 | }, 10 | "theme.NotFound.p1": { 11 | "message": "We could not find what you were looking for.", 12 | "description": "The first paragraph of the 404 page" 13 | }, 14 | "theme.NotFound.p2": { 15 | "message": "Please contact the owner of the site that linked you to the original URL and let them know their link is broken.", 16 | "description": "The 2nd paragraph of the 404 page" 17 | }, 18 | "theme.admonition.note": { 19 | "message": "note", 20 | "description": "The default label used for the Note admonition (:::note)" 21 | }, 22 | "theme.admonition.tip": { 23 | "message": "tip", 24 | "description": "The default label used for the Tip admonition (:::tip)" 25 | }, 26 | "theme.admonition.danger": { 27 | "message": "danger", 28 | "description": "The default label used for the Danger admonition (:::danger)" 29 | }, 30 | "theme.admonition.info": { 31 | "message": "info", 32 | "description": "The default label used for the Info admonition (:::info)" 33 | }, 34 | "theme.admonition.caution": { 35 | "message": "caution", 36 | "description": "The default label used for the Caution admonition (:::caution)" 37 | }, 38 | "theme.BackToTopButton.buttonAriaLabel": { 39 | "message": "Scroll back to top", 40 | "description": "The ARIA label for the back to top button" 41 | }, 42 | "theme.blog.archive.title": { 43 | "message": "Archive", 44 | "description": "The page & hero title of the blog archive page" 45 | }, 46 | "theme.blog.archive.description": { 47 | "message": "Archive", 48 | "description": "The page & hero description of the blog archive page" 49 | }, 50 | "theme.blog.paginator.navAriaLabel": { 51 | "message": "Blog list page navigation", 52 | "description": "The ARIA label for the blog pagination" 53 | }, 54 | "theme.blog.paginator.newerEntries": { 55 | "message": "Newer Entries", 56 | "description": "The label used to navigate to the newer blog posts page (previous page)" 57 | }, 58 | "theme.blog.paginator.olderEntries": { 59 | "message": "Older Entries", 60 | "description": "The label used to navigate to the older blog posts page (next page)" 61 | }, 62 | "theme.blog.post.paginator.navAriaLabel": { 63 | "message": "Blog post page navigation", 64 | "description": "The ARIA label for the blog posts pagination" 65 | }, 66 | "theme.blog.post.paginator.newerPost": { 67 | "message": "Newer Post", 68 | "description": "The blog post button label to navigate to the newer/previous post" 69 | }, 70 | "theme.blog.post.paginator.olderPost": { 71 | "message": "Older Post", 72 | "description": "The blog post button label to navigate to the older/next post" 73 | }, 74 | "theme.blog.post.plurals": { 75 | "message": "One post|{count} posts", 76 | "description": "Pluralized label for \"{count} posts\". Use as much plural forms (separated by \"|\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)" 77 | }, 78 | "theme.blog.tagTitle": { 79 | "message": "{nPosts} tagged with \"{tagName}\"", 80 | "description": "The title of the page for a blog tag" 81 | }, 82 | "theme.tags.tagsPageLink": { 83 | "message": "View All Tags", 84 | "description": "The label of the link targeting the tag list page" 85 | }, 86 | "theme.colorToggle.ariaLabel": { 87 | "message": "Switch between dark and light mode (currently {mode})", 88 | "description": "The ARIA label for the navbar color mode toggle" 89 | }, 90 | "theme.colorToggle.ariaLabel.mode.dark": { 91 | "message": "dark mode", 92 | "description": "The name for the dark color mode" 93 | }, 94 | "theme.colorToggle.ariaLabel.mode.light": { 95 | "message": "light mode", 96 | "description": "The name for the light color mode" 97 | }, 98 | "theme.docs.breadcrumbs.navAriaLabel": { 99 | "message": "Breadcrumbs", 100 | "description": "The ARIA label for the breadcrumbs" 101 | }, 102 | "theme.docs.DocCard.categoryDescription": { 103 | "message": "{count} items", 104 | "description": "The default description for a category card in the generated index about how many items this category includes" 105 | }, 106 | "theme.docs.paginator.navAriaLabel": { 107 | "message": "Docs pages navigation", 108 | "description": "The ARIA label for the docs pagination" 109 | }, 110 | "theme.docs.paginator.previous": { 111 | "message": "Previous", 112 | "description": "The label used to navigate to the previous doc" 113 | }, 114 | "theme.docs.paginator.next": { 115 | "message": "Next", 116 | "description": "The label used to navigate to the next doc" 117 | }, 118 | "theme.docs.tagDocListPageTitle.nDocsTagged": { 119 | "message": "One doc tagged|{count} docs tagged", 120 | "description": "Pluralized label for \"{count} docs tagged\". Use as much plural forms (separated by \"|\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)" 121 | }, 122 | "theme.docs.tagDocListPageTitle": { 123 | "message": "{nDocsTagged} with \"{tagName}\"", 124 | "description": "The title of the page for a docs tag" 125 | }, 126 | "theme.docs.versionBadge.label": { 127 | "message": "Version: {versionLabel}" 128 | }, 129 | "theme.common.editThisPage": { 130 | "message": "Edit this page", 131 | "description": "The link label to edit the current page" 132 | }, 133 | "theme.docs.versions.unreleasedVersionLabel": { 134 | "message": "This is unreleased documentation for {siteTitle} {versionLabel} version.", 135 | "description": "The label used to tell the user that he's browsing an unreleased doc version" 136 | }, 137 | "theme.docs.versions.unmaintainedVersionLabel": { 138 | "message": "This is documentation for {siteTitle} {versionLabel}, which is no longer actively maintained.", 139 | "description": "The label used to tell the user that he's browsing an unmaintained doc version" 140 | }, 141 | "theme.docs.versions.latestVersionSuggestionLabel": { 142 | "message": "For up-to-date documentation, see the {latestVersionLink} ({versionLabel}).", 143 | "description": "The label used to tell the user to check the latest version" 144 | }, 145 | "theme.docs.versions.latestVersionLinkLabel": { 146 | "message": "latest version", 147 | "description": "The label used for the latest version suggestion link label" 148 | }, 149 | "theme.common.headingLinkTitle": { 150 | "message": "Direct link to {heading}", 151 | "description": "Title for link to heading" 152 | }, 153 | "theme.lastUpdated.atDate": { 154 | "message": " on {date}", 155 | "description": "The words used to describe on which date a page has been last updated" 156 | }, 157 | "theme.lastUpdated.byUser": { 158 | "message": " by {user}", 159 | "description": "The words used to describe by who the page has been last updated" 160 | }, 161 | "theme.lastUpdated.lastUpdatedAtBy": { 162 | "message": "Last updated{atDate}{byUser}", 163 | "description": "The sentence used to display when a page has been last updated, and by who" 164 | }, 165 | "theme.navbar.mobileVersionsDropdown.label": { 166 | "message": "Versions", 167 | "description": "The label for the navbar versions dropdown on mobile view" 168 | }, 169 | "theme.tags.tagsListLabel": { 170 | "message": "Tags:", 171 | "description": "The label alongside a tag list" 172 | }, 173 | "theme.AnnouncementBar.closeButtonAriaLabel": { 174 | "message": "Close", 175 | "description": "The ARIA label for close button of announcement bar" 176 | }, 177 | "theme.blog.sidebar.navAriaLabel": { 178 | "message": "Blog recent posts navigation", 179 | "description": "The ARIA label for recent posts in the blog sidebar" 180 | }, 181 | "theme.CodeBlock.wordWrapToggle": { 182 | "message": "Toggle word wrap", 183 | "description": "The title attribute for toggle word wrapping button of code block lines" 184 | }, 185 | "theme.CodeBlock.copied": { 186 | "message": "Copied", 187 | "description": "The copied button label on code blocks" 188 | }, 189 | "theme.CodeBlock.copyButtonAriaLabel": { 190 | "message": "Copy code to clipboard", 191 | "description": "The ARIA label for copy code blocks button" 192 | }, 193 | "theme.CodeBlock.copy": { 194 | "message": "Copy", 195 | "description": "The copy button label on code blocks" 196 | }, 197 | "theme.DocSidebarItem.toggleCollapsedCategoryAriaLabel": { 198 | "message": "Toggle the collapsible sidebar category '{label}'", 199 | "description": "The ARIA label to toggle the collapsible sidebar category" 200 | }, 201 | "theme.NavBar.navAriaLabel": { 202 | "message": "Main", 203 | "description": "The ARIA label for the main navigation" 204 | }, 205 | "theme.blog.post.readMore": { 206 | "message": "Read More", 207 | "description": "The label used in blog post item excerpts to link to full blog posts" 208 | }, 209 | "theme.blog.post.readMoreLabel": { 210 | "message": "Read more about {title}", 211 | "description": "The ARIA label for the link to full blog posts from excerpts" 212 | }, 213 | "theme.TOCCollapsible.toggleButtonLabel": { 214 | "message": "On this page", 215 | "description": "The label used by the button on the collapsible TOC component" 216 | }, 217 | "theme.navbar.mobileLanguageDropdown.label": { 218 | "message": "Languages", 219 | "description": "The label for the mobile language switcher dropdown" 220 | }, 221 | "theme.blog.post.readingTime.plurals": { 222 | "message": "One min read|{readingTime} min read", 223 | "description": "Pluralized label for \"{readingTime} min read\". Use as much plural forms (separated by \"|\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)" 224 | }, 225 | "theme.docs.breadcrumbs.home": { 226 | "message": "Home page", 227 | "description": "The ARIA label for the home page in the breadcrumbs" 228 | }, 229 | "theme.docs.sidebar.collapseButtonTitle": { 230 | "message": "Collapse sidebar", 231 | "description": "The title attribute for collapse button of doc sidebar" 232 | }, 233 | "theme.docs.sidebar.collapseButtonAriaLabel": { 234 | "message": "Collapse sidebar", 235 | "description": "The title attribute for collapse button of doc sidebar" 236 | }, 237 | "theme.docs.sidebar.navAriaLabel": { 238 | "message": "Docs sidebar", 239 | "description": "The ARIA label for the sidebar navigation" 240 | }, 241 | "theme.docs.sidebar.expandButtonTitle": { 242 | "message": "Expand sidebar", 243 | "description": "The ARIA label and title attribute for expand button of doc sidebar" 244 | }, 245 | "theme.docs.sidebar.expandButtonAriaLabel": { 246 | "message": "Expand sidebar", 247 | "description": "The ARIA label and title attribute for expand button of doc sidebar" 248 | }, 249 | "theme.docs.sidebar.closeSidebarButtonAriaLabel": { 250 | "message": "Close navigation bar", 251 | "description": "The ARIA label for close button of mobile sidebar" 252 | }, 253 | "theme.docs.sidebar.toggleSidebarButtonAriaLabel": { 254 | "message": "Toggle navigation bar", 255 | "description": "The ARIA label for hamburger menu button of mobile navigation" 256 | }, 257 | "theme.navbar.mobileSidebarSecondaryMenu.backButtonLabel": { 258 | "message": "← Back to main menu", 259 | "description": "The label of the back button to return to main menu, inside the mobile navbar sidebar secondary menu (notably used to display the docs sidebar)" 260 | }, 261 | "theme.ErrorPageContent.tryAgain": { 262 | "message": "Try again", 263 | "description": "The label of the button to try again rendering when the React error boundary captures an error" 264 | }, 265 | "theme.common.skipToMainContent": { 266 | "message": "Skip to main content", 267 | "description": "The skip to content label used for accessibility, allowing to rapidly navigate to main content with keyboard tab/enter navigation" 268 | }, 269 | "theme.tags.tagsPageTitle": { 270 | "message": "Tags", 271 | "description": "The title of the tag list page" 272 | } 273 | } 274 | -------------------------------------------------------------------------------- /Apps/docs/i18n/en/docusaurus-plugin-content-docs/current.json: -------------------------------------------------------------------------------- 1 | { 2 | "version.label": { 3 | "message": "Next", 4 | "description": "The label for version current" 5 | }, 6 | "sidebar.tutorialSidebar.category.Guide": { 7 | "message": "Guide", 8 | "description": "The label for category Guide in sidebar tutorialSidebar" 9 | }, 10 | "sidebar.tutorialSidebar.category.Reference": { 11 | "message": "Reference", 12 | "description": "The label for category Reference in sidebar tutorialSidebar" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Apps/docs/i18n/en/docusaurus-theme-classic/footer.json: -------------------------------------------------------------------------------- 1 | { 2 | "link.title.Docs": { 3 | "message": "Docs", 4 | "description": "The title of the footer links column with title=Docs in the footer" 5 | }, 6 | "link.title.Community": { 7 | "message": "Community", 8 | "description": "The title of the footer links column with title=Community in the footer" 9 | }, 10 | "link.title.More": { 11 | "message": "More", 12 | "description": "The title of the footer links column with title=More in the footer" 13 | }, 14 | "link.item.label.Get Started": { 15 | "message": "Get Started", 16 | "description": "The label of footer link with label=Get Started linking to /docs/intro" 17 | }, 18 | "link.item.label.Stack Overflow": { 19 | "message": "Stack Overflow", 20 | "description": "The label of footer link with label=Stack Overflow linking to https://stackoverflow.com/questions/tagged/quackscript" 21 | }, 22 | "link.item.label.Twitter": { 23 | "message": "Twitter", 24 | "description": "The label of footer link with label=Twitter linking to https://twitter.com/quackscript" 25 | }, 26 | "link.item.label.GitHub": { 27 | "message": "GitHub", 28 | "description": "The label of footer link with label=GitHub linking to https://github.com/niv3k-el-pato/quackscript" 29 | }, 30 | "copyright": { 31 | "message": "Copyright © 2023 QuackScript", 32 | "description": "The footer copyright" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Apps/docs/i18n/en/docusaurus-theme-classic/navbar.json: -------------------------------------------------------------------------------- 1 | { 2 | "logo.alt": { 3 | "message": "The JS killer", 4 | "description": "The alt text of navbar logo" 5 | }, 6 | "item.label.GitHub": { 7 | "message": "GitHub", 8 | "description": "Navbar item with label GitHub" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Apps/docs/i18n/es/code.json: -------------------------------------------------------------------------------- 1 | { 2 | "theme.ErrorPageContent.title": { 3 | "message": "This page crashed.", 4 | "description": "The title of the fallback page when the page crashed" 5 | }, 6 | "theme.NotFound.title": { 7 | "message": "Página No Encontrada", 8 | "description": "The title of the 404 page" 9 | }, 10 | "theme.NotFound.p1": { 11 | "message": "No pudimos encontrar lo que buscaba.", 12 | "description": "The first paragraph of the 404 page" 13 | }, 14 | "theme.NotFound.p2": { 15 | "message": "Comuníquese con el dueño del sitio que lo vinculó a la URL original y hágale saber que su vínculo está roto.", 16 | "description": "The 2nd paragraph of the 404 page" 17 | }, 18 | "theme.admonition.note": { 19 | "message": "note", 20 | "description": "The default label used for the Note admonition (:::note)" 21 | }, 22 | "theme.admonition.tip": { 23 | "message": "tip", 24 | "description": "The default label used for the Tip admonition (:::tip)" 25 | }, 26 | "theme.admonition.danger": { 27 | "message": "danger", 28 | "description": "The default label used for the Danger admonition (:::danger)" 29 | }, 30 | "theme.admonition.info": { 31 | "message": "info", 32 | "description": "The default label used for the Info admonition (:::info)" 33 | }, 34 | "theme.admonition.caution": { 35 | "message": "caution", 36 | "description": "The default label used for the Caution admonition (:::caution)" 37 | }, 38 | "theme.blog.archive.title": { 39 | "message": "Archivo", 40 | "description": "The page & hero title of the blog archive page" 41 | }, 42 | "theme.blog.archive.description": { 43 | "message": "Archivo", 44 | "description": "The page & hero description of the blog archive page" 45 | }, 46 | "theme.BackToTopButton.buttonAriaLabel": { 47 | "message": "Volver al principio", 48 | "description": "The ARIA label for the back to top button" 49 | }, 50 | "theme.blog.paginator.navAriaLabel": { 51 | "message": "Navegación por la página de la lista de blogs ", 52 | "description": "The ARIA label for the blog pagination" 53 | }, 54 | "theme.blog.paginator.newerEntries": { 55 | "message": "Entradas más recientes", 56 | "description": "The label used to navigate to the newer blog posts page (previous page)" 57 | }, 58 | "theme.blog.paginator.olderEntries": { 59 | "message": "Entradas más antiguas", 60 | "description": "The label used to navigate to the older blog posts page (next page)" 61 | }, 62 | "theme.blog.post.paginator.navAriaLabel": { 63 | "message": "Barra de paginación de publicaciones del blog", 64 | "description": "The ARIA label for the blog posts pagination" 65 | }, 66 | "theme.blog.post.paginator.newerPost": { 67 | "message": "Publicación más reciente", 68 | "description": "The blog post button label to navigate to the newer/previous post" 69 | }, 70 | "theme.blog.post.paginator.olderPost": { 71 | "message": "Publicación más antigua", 72 | "description": "The blog post button label to navigate to the older/next post" 73 | }, 74 | "theme.blog.post.plurals": { 75 | "message": "Una publicación|{count} publicaciones", 76 | "description": "Pluralized label for \"{count} posts\". Use as much plural forms (separated by \"|\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)" 77 | }, 78 | "theme.blog.tagTitle": { 79 | "message": "{nPosts} etiquetados con \"{tagName}\"", 80 | "description": "The title of the page for a blog tag" 81 | }, 82 | "theme.tags.tagsPageLink": { 83 | "message": "Ver Todas las Etiquetas", 84 | "description": "The label of the link targeting the tag list page" 85 | }, 86 | "theme.colorToggle.ariaLabel": { 87 | "message": "Switch between dark and light mode (currently {mode})", 88 | "description": "The ARIA label for the navbar color mode toggle" 89 | }, 90 | "theme.colorToggle.ariaLabel.mode.dark": { 91 | "message": "dark mode", 92 | "description": "The name for the dark color mode" 93 | }, 94 | "theme.colorToggle.ariaLabel.mode.light": { 95 | "message": "light mode", 96 | "description": "The name for the light color mode" 97 | }, 98 | "theme.docs.breadcrumbs.navAriaLabel": { 99 | "message": "Breadcrumbs", 100 | "description": "The ARIA label for the breadcrumbs" 101 | }, 102 | "theme.docs.DocCard.categoryDescription": { 103 | "message": "{count} items", 104 | "description": "The default description for a category card in the generated index about how many items this category includes" 105 | }, 106 | "theme.docs.paginator.navAriaLabel": { 107 | "message": "Navegación de páginas de documentos", 108 | "description": "The ARIA label for the docs pagination" 109 | }, 110 | "theme.docs.paginator.previous": { 111 | "message": "Anterior", 112 | "description": "The label used to navigate to the previous doc" 113 | }, 114 | "theme.docs.paginator.next": { 115 | "message": "Siguiente", 116 | "description": "The label used to navigate to the next doc" 117 | }, 118 | "theme.docs.tagDocListPageTitle.nDocsTagged": { 119 | "message": "Un documento etiquetado|{count} documentos etiquetados", 120 | "description": "Pluralized label for \"{count} docs tagged\". Use as much plural forms (separated by \"|\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)" 121 | }, 122 | "theme.docs.tagDocListPageTitle": { 123 | "message": "{nDocsTagged} con \"{tagName}\"", 124 | "description": "The title of the page for a docs tag" 125 | }, 126 | "theme.docs.versionBadge.label": { 127 | "message": "Version: {versionLabel}" 128 | }, 129 | "theme.docs.versions.unreleasedVersionLabel": { 130 | "message": "Esta es documentación sin liberar para {siteTitle} {versionLabel} versión.", 131 | "description": "The label used to tell the user that he's browsing an unreleased doc version" 132 | }, 133 | "theme.docs.versions.unmaintainedVersionLabel": { 134 | "message": "Esta es documentación para {siteTitle} {versionLabel}, que ya no se mantiene activamente.", 135 | "description": "The label used to tell the user that he's browsing an unmaintained doc version" 136 | }, 137 | "theme.docs.versions.latestVersionSuggestionLabel": { 138 | "message": "Para la documentación actualizada, vea {latestVersionLink} ({versionLabel}).", 139 | "description": "The label used to tell the user to check the latest version" 140 | }, 141 | "theme.docs.versions.latestVersionLinkLabel": { 142 | "message": "última versión", 143 | "description": "The label used for the latest version suggestion link label" 144 | }, 145 | "theme.common.editThisPage": { 146 | "message": "Editar esta página", 147 | "description": "The link label to edit the current page" 148 | }, 149 | "theme.common.headingLinkTitle": { 150 | "message": "Enlace directo al {heading}", 151 | "description": "Title for link to heading" 152 | }, 153 | "theme.lastUpdated.atDate": { 154 | "message": " en {date}", 155 | "description": "The words used to describe on which date a page has been last updated" 156 | }, 157 | "theme.lastUpdated.byUser": { 158 | "message": " por {user}", 159 | "description": "The words used to describe by who the page has been last updated" 160 | }, 161 | "theme.lastUpdated.lastUpdatedAtBy": { 162 | "message": "Última actualización{atDate}{byUser}", 163 | "description": "The sentence used to display when a page has been last updated, and by who" 164 | }, 165 | "theme.navbar.mobileVersionsDropdown.label": { 166 | "message": "Versiones", 167 | "description": "The label for the navbar versions dropdown on mobile view" 168 | }, 169 | "theme.tags.tagsListLabel": { 170 | "message": "Etiquetas:", 171 | "description": "The label alongside a tag list" 172 | }, 173 | "theme.AnnouncementBar.closeButtonAriaLabel": { 174 | "message": "Cerrar", 175 | "description": "The ARIA label for close button of announcement bar" 176 | }, 177 | "theme.blog.sidebar.navAriaLabel": { 178 | "message": "Navegación de publicaciones recientes", 179 | "description": "The ARIA label for recent posts in the blog sidebar" 180 | }, 181 | "theme.CodeBlock.copied": { 182 | "message": "Copiado", 183 | "description": "The copied button label on code blocks" 184 | }, 185 | "theme.CodeBlock.copyButtonAriaLabel": { 186 | "message": "Copiar código al portapapeles", 187 | "description": "The ARIA label for copy code blocks button" 188 | }, 189 | "theme.CodeBlock.copy": { 190 | "message": "Copiar", 191 | "description": "The copy button label on code blocks" 192 | }, 193 | "theme.CodeBlock.wordWrapToggle": { 194 | "message": "Toggle word wrap", 195 | "description": "The title attribute for toggle word wrapping button of code block lines" 196 | }, 197 | "theme.DocSidebarItem.toggleCollapsedCategoryAriaLabel": { 198 | "message": "Toggle the collapsible sidebar category '{label}'", 199 | "description": "The ARIA label to toggle the collapsible sidebar category" 200 | }, 201 | "theme.NavBar.navAriaLabel": { 202 | "message": "Main", 203 | "description": "The ARIA label for the main navigation" 204 | }, 205 | "theme.navbar.mobileLanguageDropdown.label": { 206 | "message": "Languages", 207 | "description": "The label for the mobile language switcher dropdown" 208 | }, 209 | "theme.TOCCollapsible.toggleButtonLabel": { 210 | "message": "En esta página", 211 | "description": "The label used by the button on the collapsible TOC component" 212 | }, 213 | "theme.blog.post.readMore": { 214 | "message": "Leer Más", 215 | "description": "The label used in blog post item excerpts to link to full blog posts" 216 | }, 217 | "theme.blog.post.readMoreLabel": { 218 | "message": "Read more about {title}", 219 | "description": "The ARIA label for the link to full blog posts from excerpts" 220 | }, 221 | "theme.blog.post.readingTime.plurals": { 222 | "message": "Lectura de un minuto|{readingTime} min de lectura", 223 | "description": "Pluralized label for \"{readingTime} min read\". Use as much plural forms (separated by \"|\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)" 224 | }, 225 | "theme.docs.breadcrumbs.home": { 226 | "message": "Home page", 227 | "description": "The ARIA label for the home page in the breadcrumbs" 228 | }, 229 | "theme.docs.sidebar.collapseButtonTitle": { 230 | "message": "Colapsar barra lateral", 231 | "description": "The title attribute for collapse button of doc sidebar" 232 | }, 233 | "theme.docs.sidebar.collapseButtonAriaLabel": { 234 | "message": "Colapsar barra lateral", 235 | "description": "The title attribute for collapse button of doc sidebar" 236 | }, 237 | "theme.docs.sidebar.navAriaLabel": { 238 | "message": "Docs sidebar", 239 | "description": "The ARIA label for the sidebar navigation" 240 | }, 241 | "theme.docs.sidebar.closeSidebarButtonAriaLabel": { 242 | "message": "Close navigation bar", 243 | "description": "The ARIA label for close button of mobile sidebar" 244 | }, 245 | "theme.navbar.mobileSidebarSecondaryMenu.backButtonLabel": { 246 | "message": "← Volver al menú principal", 247 | "description": "The label of the back button to return to main menu, inside the mobile navbar sidebar secondary menu (notably used to display the docs sidebar)" 248 | }, 249 | "theme.docs.sidebar.toggleSidebarButtonAriaLabel": { 250 | "message": "Toggle navigation bar", 251 | "description": "The ARIA label for hamburger menu button of mobile navigation" 252 | }, 253 | "theme.docs.sidebar.expandButtonTitle": { 254 | "message": "Expandir barra lateral", 255 | "description": "The ARIA label and title attribute for expand button of doc sidebar" 256 | }, 257 | "theme.docs.sidebar.expandButtonAriaLabel": { 258 | "message": "Expandir barra lateral", 259 | "description": "The ARIA label and title attribute for expand button of doc sidebar" 260 | }, 261 | "theme.ErrorPageContent.tryAgain": { 262 | "message": "Try again", 263 | "description": "The label of the button to try again rendering when the React error boundary captures an error" 264 | }, 265 | "theme.common.skipToMainContent": { 266 | "message": "Saltar al contenido principal", 267 | "description": "The skip to content label used for accessibility, allowing to rapidly navigate to main content with keyboard tab/enter navigation" 268 | }, 269 | "theme.tags.tagsPageTitle": { 270 | "message": "Etiquetas", 271 | "description": "The title of the tag list page" 272 | } 273 | } 274 | -------------------------------------------------------------------------------- /Apps/docs/i18n/es/docusaurus-plugin-content-docs/current.json: -------------------------------------------------------------------------------- 1 | { 2 | "version.label": { 3 | "message": "Next", 4 | "description": "The label for version current" 5 | }, 6 | "sidebar.tutorialSidebar.category.Guide": { 7 | "message": "Guide", 8 | "description": "The label for category Guide in sidebar tutorialSidebar" 9 | }, 10 | "sidebar.tutorialSidebar.category.Reference": { 11 | "message": "Reference", 12 | "description": "The label for category Reference in sidebar tutorialSidebar" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Apps/docs/i18n/es/docusaurus-plugin-content-docs/current/GetStarted.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 1 3 | slug: / 4 | --- 5 | 6 | # Quackscript 7 | 8 | :::danger En Desarrollo 9 | QuackScript aún está en desarrollo, así que las cosas **cambiarán** 10 | ::: 11 | 12 | ## Comenzando 13 | 14 | Comenzar en el playground de QuackScript **[Playground de QuackScript](https://quackscript.com)**. 15 | -------------------------------------------------------------------------------- /Apps/docs/i18n/es/docusaurus-plugin-content-docs/current/Guide/ControlFlow.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 3 3 | --- 4 | 5 | # Control de flujo 6 | 7 | QuackScript soporta un par de sentencias de control de flujo que proveen flexibilidad en su aplicación. 8 | 9 | ## Sentencia If 10 | 11 | Una sentencia if ejecutará las sentencias contenidas en el bloque de código si la condición es `true`. La condición puede ser cualquier expresión que evalue a `true` 12 | 13 | ```js 14 | if ( /* condición */ ) { 15 | // sentencias 16 | } 17 | ``` 18 | 19 | La sentencia if permite un `else` opcional cuyo bloque de código se ejecutarási la condición del if es falsa. 20 | 21 | ```js 22 | if ( /* condición */ ) { 23 | // esto se ejecutará si la condición es verdadera 24 | } else { 25 | // esto se ejecutará si la condición es falsa 26 | } 27 | ``` -------------------------------------------------------------------------------- /Apps/docs/i18n/es/docusaurus-plugin-content-docs/current/Guide/Functions.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 2 3 | --- 4 | 5 | # Funciones 6 | 7 | Una función contiene una serie de sentencias que son ejecutadas cuando la función es llamada. Cada función contiene su propio ámbito que es eliminado de la memoria luego de su ejecución. 8 | 9 | Las funciones en Quackscript son consideradas ciudadanos de primera clase, pueden ser pasadas a otras funciones, devueltas desde funciones y asignadas a variables. 10 | 11 | 12 | ## Declando una función 13 | 14 | Para declarar una función en QuackScript debes indicar el cuerpo de función y 0 o más parámetros. Las funciones necesitan ser asignadas a variables para ser utilizadas. 15 | 16 | ``` 17 | QUACK fnEjemplo <- () > { 18 | quackprint('Hola mundo')🦆 19 | }🦆 20 | ``` 21 | 22 | ## Devolución de valor 23 | 24 | Una función sin la sentencia `return` siempre va a devolver `nothing`. Un `return` en una función permite devolver un valor específico. 25 | 26 | ```js 27 | quack devolverQuack <- () > { 28 | return 'quack'🦆 29 | }🦆 30 | ``` 31 | 32 | ## Parámetros 33 | 34 | Una función puede tener 0 o más parámetros. Cuando una función es llamada la misma cantidad de argumentos deben ser pasados. 35 | 36 | ```js 37 | quack sumar <- (primero, segundo) > { 38 | return primero + segundo🦆 39 | }🦆 40 | 41 | 42 | add(1, 2)🦆 43 | ``` 44 | -------------------------------------------------------------------------------- /Apps/docs/i18n/es/docusaurus-plugin-content-docs/current/Guide/GrammarAndTypes.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 1 3 | --- 4 | 5 | # Sintáxis y tipos 6 | 7 | Este capítulo analiza la gramática básica, declaración de variables, los tipos de datos y los literales de QuackScript. 8 | 9 | ## Esencial 10 | 11 | En QuackScript cada sentencia debe terminar con 🦆 12 | 13 | ## Comentarios 14 | 15 | Un comentario en QuackScript comienza con `//` y llega hasta el final de la línea. 16 | Los comentarios no se ejecutan, existen para hacer anotaciones en su código. Es una buena práctica explicar partes complejas del código con comentarios. 17 | 18 | ```js 19 | // esto es un comentario 20 | ``` 21 | 22 | También puede escribir comentarios multilínea comenzando con `/*` y terminando con `*/` 23 | 24 | ```js 25 | /* 26 | 27 | esto es un comentario multilínea 28 | 29 | */ 30 | ``` 31 | 32 | ## Declaraciones 33 | 34 | QuackScript soporta dos tipos de declaraciones. 35 | 36 | `quack` Declara una variable. 37 | 38 | `QUACK` Declara una constante de solo lectura que no puede ser modificada. 39 | 40 | ### Declaraciones e inicializaciones 41 | 42 | Todas las variables deben ser declaradas antes de ser utilizadas, de otra forma se lanzará una excepción. 43 | 44 | Puedes usar `quack` y `QUACK` para declarar variables con ámbito de bloque. (Ver *ámbito de variables* debajo.) 45 | 46 | Para declarar una variable debes utilizar la siguiente sintáxis: 47 | 48 | ```js 49 | quack a🦆 50 | ``` 51 | 52 | Una variable puede ser declarada e inicializada en la misma línea usando la siguiente sintáxis: 53 | 54 | ```js 55 | quack a <- 'hola mundo'🦆 56 | ``` 57 | 58 | Una constante siempre debe inicializarse cuando es declarada. 59 | ```js 60 | QUACK a <- 'hola mundo'🦆 61 | ``` 62 | 63 | ### Ámbito de variables 64 | 65 | En QuackScript las variables pertenecen al ámbito global o al de bloque de código. 66 | 67 | Un bloque de código es definido como un par de `{` `}` 68 | 69 | ```js 70 | quack a <- 'hola mundo'🦆 71 | 72 | QUACK b <- () { 73 | QUACK c <- 32🦆 74 | a <- 'adiós mundo'🦆 75 | }🦆 76 | ``` 77 | 78 | En el ejemplo anterior la variable `a` está en el ámbito global, lo que significa que es accesible desde cualquier lugar del archivo. La variable `c` está declarada dentro de un bloque de código, lo que significa que solamente es accesible dentro de ese mismo bloque de código. Las variables son eliminadas de la memoria luego de que el bloque de código al que pertenecen finaliza su ejecución, entonces tras la ejecución de la función `b` la variable `c` ya no está en la memoria y `a` ha sido cambiada a `'adiós mundo'`. 79 | 80 | ## Tipos de dato 81 | 82 | Quackscript proporciona los siguientes tipos de dato: 83 | 84 | 1. `boolean` - `true` y `false`. 85 | 1. `nothing` - Un tipo de dato que indica la falta de un valor. Una variable no inicializada contiene `nothing` y las funciones que no devuelven un valor devolverán `nothing` 86 | 1. `number` - Un número entero o de coma flotante. Ej. `32` o `32.5` 87 | 1. `text` - Una secuencia de caracteres. Ej. `'Hola Mundo'` 88 | 1. `function` - La definición de una función. 89 | 1. `object` - *[no implementado]* 90 | 1. `list` - *[no implementado]* Una secuencia de elementos con el mismo tipo de dato 91 | 1. `vector2` - *[no implementado]* Un vector de 2 dimensiones que contiene `x` e `y` `número` valores 92 | 1. `vector3` - *[no implementado]* Un vector de 3 dimensiones que contiene `x`, `y` y `z` `número` valores 93 | 1. `dictionary` - *[no implementado]* Una colección de pares clave valor donde cada clave es unica y del mismo tipo de dato 94 | 95 | ### Tipado de variables 96 | 97 | Cada variable tendrá un tipo de dato asociado a ella. Puede explícitamente definir el tipo de dato luego del nombre de una variable o dejar que QuackScript infiera el tipo de dato por usted. 98 | 99 | ```js 100 | QUACK a:text <- 'hola mundo'🦆 101 | 102 | // esto va a generar el mismo tipo de dato para la variable que el código de abajo 103 | // QuackScript infiere el tipo de dato de la inicialización 104 | QUACK b <- 'hola mundo'🦆 105 | ``` 106 | 107 | QuackScript es un lenguaje fuertemente tipado y de tipado estático lo que significa que una vez que se define el tipo de dato de una variable no podrá ser asignado un valor de otro tipo. 108 | 109 | ```js 110 | quack a:text <- 'hola mundo'🦆 111 | 112 | // La siguiente instrucción lanzará un error 113 | a <- 23🦆 114 | ``` 115 | 116 | Una variable puede ser opcional lo que le permite contener un valor del tipo definido o `nothing`. Puede declarar una variable como opcional agregando un `?` luego del identificador de la variable. 117 | ```js 118 | quack puedeSerNothing?:string🦆 119 | // En este punto 'puedeSerNothing' es 'nothing' 120 | 121 | couldBeNothing <- 'hola mundo'🦆 122 | // En este punto 'couldBeNothing' es 'hola mundo' 123 | ``` -------------------------------------------------------------------------------- /Apps/docs/i18n/es/docusaurus-theme-classic/footer.json: -------------------------------------------------------------------------------- 1 | { 2 | "link.title.Docs": { 3 | "message": "Docs", 4 | "description": "The title of the footer links column with title=Docs in the footer" 5 | }, 6 | "link.title.Community": { 7 | "message": "Community", 8 | "description": "The title of the footer links column with title=Community in the footer" 9 | }, 10 | "link.title.More": { 11 | "message": "More", 12 | "description": "The title of the footer links column with title=More in the footer" 13 | }, 14 | "link.item.label.Get Started": { 15 | "message": "Get Started", 16 | "description": "The label of footer link with label=Get Started linking to /docs/intro" 17 | }, 18 | "link.item.label.Stack Overflow": { 19 | "message": "Stack Overflow", 20 | "description": "The label of footer link with label=Stack Overflow linking to https://stackoverflow.com/questions/tagged/quackscript" 21 | }, 22 | "link.item.label.Twitter": { 23 | "message": "Twitter", 24 | "description": "The label of footer link with label=Twitter linking to https://twitter.com/quackscript" 25 | }, 26 | "link.item.label.GitHub": { 27 | "message": "GitHub", 28 | "description": "The label of footer link with label=GitHub linking to https://github.com/niv3k-el-pato/quackscript" 29 | }, 30 | "copyright": { 31 | "message": "Copyright © 2023 QuackScript", 32 | "description": "The footer copyright" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Apps/docs/i18n/es/docusaurus-theme-classic/navbar.json: -------------------------------------------------------------------------------- 1 | { 2 | "logo.alt": { 3 | "message": "The JS killer", 4 | "description": "The alt text of navbar logo" 5 | }, 6 | "item.label.GitHub": { 7 | "message": "GitHub", 8 | "description": "Navbar item with label GitHub" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Apps/docs/i18n/quack/code.json: -------------------------------------------------------------------------------- 1 | { 2 | "theme.ErrorPageContent.title": { 3 | "message": "Quack quack quack quack.", 4 | "description": "The title of the fallback page when the page crashed" 5 | }, 6 | "theme.NotFound.title": { 7 | "message": "Quack quack quack", 8 | "description": "The title of the 404 page" 9 | }, 10 | "theme.NotFound.p1": { 11 | "message": "quack quack quack quack quack quack.", 12 | "description": "The first paragraph of the 404 page" 13 | }, 14 | "theme.NotFound.p2": { 15 | "message": "quack quack quack quack.", 16 | "description": "The 2nd paragraph of the 404 page" 17 | }, 18 | "theme.admonition.note": { 19 | "message": "quack", 20 | "description": "The default label used for the Note admonition (:::note)" 21 | }, 22 | "theme.admonition.tip": { 23 | "message": "quack", 24 | "description": "The default label used for the Tip admonition (:::tip)" 25 | }, 26 | "theme.admonition.danger": { 27 | "message": "quack", 28 | "description": "The default label used for the Danger admonition (:::danger)" 29 | }, 30 | "theme.admonition.info": { 31 | "message": "quack", 32 | "description": "The default label used for the Info admonition (:::info)" 33 | }, 34 | "theme.admonition.caution": { 35 | "message": "quack", 36 | "description": "The default label used for the Caution admonition (:::caution)" 37 | }, 38 | "theme.blog.archive.title": { 39 | "message": "quack", 40 | "description": "The page & hero title of the blog archive page" 41 | }, 42 | "theme.blog.archive.description": { 43 | "message": "Quack", 44 | "description": "The page & hero description of the blog archive page" 45 | }, 46 | "theme.BackToTopButton.buttonAriaLabel": { 47 | "message": "Quack quack quack quack", 48 | "description": "The ARIA label for the back to top button" 49 | }, 50 | "theme.blog.paginator.navAriaLabel": { 51 | "message": "Quack quack quack quack", 52 | "description": "The ARIA label for the blog pagination" 53 | }, 54 | "theme.blog.paginator.newerEntries": { 55 | "message": "Quack Quack", 56 | "description": "The label used to navigate to the newer blog posts page (previous page)" 57 | }, 58 | "theme.blog.paginator.olderEntries": { 59 | "message": "Quack quack", 60 | "description": "The label used to navigate to the older blog posts page (next page)" 61 | }, 62 | "theme.blog.post.paginator.navAriaLabel": { 63 | "message": "Quack quack quack quack", 64 | "description": "The ARIA label for the blog posts pagination" 65 | }, 66 | "theme.blog.post.paginator.newerPost": { 67 | "message": "Quack quack", 68 | "description": "The blog post button label to navigate to the newer/previous post" 69 | }, 70 | "theme.blog.post.paginator.olderPost": { 71 | "message": "Quack quack", 72 | "description": "The blog post button label to navigate to the older/next post" 73 | }, 74 | "theme.blog.post.plurals": { 75 | "message": "Quack quack|{count} quack", 76 | "description": "Pluralized label for \"{count} posts\". Use as much plural forms (separated by \"|\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)" 77 | }, 78 | "theme.blog.tagTitle": { 79 | "message": "{nPosts} quack quack \"{tagName}\"", 80 | "description": "The title of the page for a blog tag" 81 | }, 82 | "theme.tags.tagsPageLink": { 83 | "message": "Quack Quack Quack", 84 | "description": "The label of the link targeting the tag list page" 85 | }, 86 | "theme.colorToggle.ariaLabel": { 87 | "message": "Quack quack quack quack quack quack (quack {mode})", 88 | "description": "The ARIA label for the navbar color mode toggle" 89 | }, 90 | "theme.colorToggle.ariaLabel.mode.dark": { 91 | "message": "quack quack", 92 | "description": "The name for the dark color mode" 93 | }, 94 | "theme.colorToggle.ariaLabel.mode.light": { 95 | "message": "quack quack", 96 | "description": "The name for the light color mode" 97 | }, 98 | "theme.docs.breadcrumbs.navAriaLabel": { 99 | "message": "Quack", 100 | "description": "The ARIA label for the breadcrumbs" 101 | }, 102 | "theme.docs.DocCard.categoryDescription": { 103 | "message": "{count} quack", 104 | "description": "The default description for a category card in the generated index about how many items this category includes" 105 | }, 106 | "theme.docs.paginator.navAriaLabel": { 107 | "message": "Quack quack quack", 108 | "description": "The ARIA label for the docs pagination" 109 | }, 110 | "theme.docs.paginator.previous": { 111 | "message": "Quack", 112 | "description": "The label used to navigate to the previous doc" 113 | }, 114 | "theme.docs.paginator.next": { 115 | "message": "Quack", 116 | "description": "The label used to navigate to the next doc" 117 | }, 118 | "theme.docs.tagDocListPageTitle.nDocsTagged": { 119 | "message": "Quack quack quack|{count} quack quack", 120 | "description": "Pluralized label for \"{count} docs tagged\". Use as much plural forms (separated by \"|\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)" 121 | }, 122 | "theme.docs.tagDocListPageTitle": { 123 | "message": "{nDocsTagged} quack \"{tagName}\"", 124 | "description": "The title of the page for a docs tag" 125 | }, 126 | "theme.docs.versionBadge.label": { 127 | "message": "Quack: {versionLabel}" 128 | }, 129 | "theme.docs.versions.unreleasedVersionLabel": { 130 | "message": "Quack quack quack quack quack {siteTitle} {versionLabel} quack.", 131 | "description": "The label used to tell the user that he's browsing an unreleased doc version" 132 | }, 133 | "theme.docs.versions.unmaintainedVersionLabel": { 134 | "message": "Quack quack quack quack {siteTitle} {versionLabel}, quack quack quack quack quack quack.", 135 | "description": "The label used to tell the user that he's browsing an unmaintained doc version" 136 | }, 137 | "theme.docs.versions.latestVersionSuggestionLabel": { 138 | "message": "Quack quack-quack-quack quack, quack quack {latestVersionLink} ({versionLabel}).", 139 | "description": "The label used to tell the user to check the latest version" 140 | }, 141 | "theme.docs.versions.latestVersionLinkLabel": { 142 | "message": "quack quack", 143 | "description": "The label used for the latest version suggestion link label" 144 | }, 145 | "theme.common.editThisPage": { 146 | "message": "Quack quack quack", 147 | "description": "The link label to edit the current page" 148 | }, 149 | "theme.common.headingLinkTitle": { 150 | "message": "Quack quack quack {heading}", 151 | "description": "Title for link to heading" 152 | }, 153 | "theme.lastUpdated.atDate": { 154 | "message": " quack {date}", 155 | "description": "The words used to describe on which date a page has been last updated" 156 | }, 157 | "theme.lastUpdated.byUser": { 158 | "message": " quack {user}", 159 | "description": "The words used to describe by who the page has been last updated" 160 | }, 161 | "theme.lastUpdated.lastUpdatedAtBy": { 162 | "message": "Quack quack{atDate}{byUser}", 163 | "description": "The sentence used to display when a page has been last updated, and by who" 164 | }, 165 | "theme.navbar.mobileVersionsDropdown.label": { 166 | "message": "Quack", 167 | "description": "The label for the navbar versions dropdown on mobile view" 168 | }, 169 | "theme.tags.tagsListLabel": { 170 | "message": "Quack:", 171 | "description": "The label alongside a tag list" 172 | }, 173 | "theme.AnnouncementBar.closeButtonAriaLabel": { 174 | "message": "Quack", 175 | "description": "The ARIA label for close button of announcement bar" 176 | }, 177 | "theme.blog.sidebar.navAriaLabel": { 178 | "message": "Quack quack quack quack", 179 | "description": "The ARIA label for recent posts in the blog sidebar" 180 | }, 181 | "theme.CodeBlock.copied": { 182 | "message": "Quack", 183 | "description": "The copied button label on code blocks" 184 | }, 185 | "theme.CodeBlock.copyButtonAriaLabel": { 186 | "message": "Quack quack quack quack", 187 | "description": "The ARIA label for copy code blocks button" 188 | }, 189 | "theme.CodeBlock.copy": { 190 | "message": "Quack", 191 | "description": "The copy button label on code blocks" 192 | }, 193 | "theme.CodeBlock.wordWrapToggle": { 194 | "message": "Quack quack quack", 195 | "description": "The title attribute for toggle word wrapping button of code block lines" 196 | }, 197 | "theme.DocSidebarItem.toggleCollapsedCategoryAriaLabel": { 198 | "message": "Quack quack quack quack quack '{label}'", 199 | "description": "The ARIA label to toggle the collapsible sidebar category" 200 | }, 201 | "theme.NavBar.navAriaLabel": { 202 | "message": "Quack", 203 | "description": "The ARIA label for the main navigation" 204 | }, 205 | "theme.navbar.mobileLanguageDropdown.label": { 206 | "message": "Quack", 207 | "description": "The label for the mobile language switcher dropdown" 208 | }, 209 | "theme.TOCCollapsible.toggleButtonLabel": { 210 | "message": "Quack quack quack", 211 | "description": "The label used by the button on the collapsible TOC component" 212 | }, 213 | "theme.blog.post.readMore": { 214 | "message": "Quack quack", 215 | "description": "The label used in blog post item excerpts to link to full blog posts" 216 | }, 217 | "theme.blog.post.readMoreLabel": { 218 | "message": "Quack quack quack {title}", 219 | "description": "The ARIA label for the link to full blog posts from excerpts" 220 | }, 221 | "theme.blog.post.readingTime.plurals": { 222 | "message": "Quack quack quack|{readingTime} quack quack", 223 | "description": "Pluralized label for \"{readingTime} min read\". Use as much plural forms (separated by \"|\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)" 224 | }, 225 | "theme.docs.breadcrumbs.home": { 226 | "message": "Quack quack", 227 | "description": "The ARIA label for the home page in the breadcrumbs" 228 | }, 229 | "theme.docs.sidebar.collapseButtonTitle": { 230 | "message": "Quack quack", 231 | "description": "The title attribute for collapse button of doc sidebar" 232 | }, 233 | "theme.docs.sidebar.collapseButtonAriaLabel": { 234 | "message": "Quack quack", 235 | "description": "The title attribute for collapse button of doc sidebar" 236 | }, 237 | "theme.docs.sidebar.navAriaLabel": { 238 | "message": "Quack quack", 239 | "description": "The ARIA label for the sidebar navigation" 240 | }, 241 | "theme.docs.sidebar.closeSidebarButtonAriaLabel": { 242 | "message": "Quack quack quack", 243 | "description": "The ARIA label for close button of mobile sidebar" 244 | }, 245 | "theme.navbar.mobileSidebarSecondaryMenu.backButtonLabel": { 246 | "message": "← Quack quack quack quack", 247 | "description": "The label of the back button to return to main menu, inside the mobile navbar sidebar secondary menu (notably used to display the docs sidebar)" 248 | }, 249 | "theme.docs.sidebar.toggleSidebarButtonAriaLabel": { 250 | "message": "quack quack quack", 251 | "description": "The ARIA label for hamburger menu button of mobile navigation" 252 | }, 253 | "theme.docs.sidebar.expandButtonTitle": { 254 | "message": "quack quack", 255 | "description": "The ARIA label and title attribute for expand button of doc sidebar" 256 | }, 257 | "theme.docs.sidebar.expandButtonAriaLabel": { 258 | "message": "quack quack quack", 259 | "description": "The ARIA label and title attribute for expand button of doc sidebar" 260 | }, 261 | "theme.ErrorPageContent.tryAgain": { 262 | "message": "quack quack", 263 | "description": "The label of the button to try again rendering when the React error boundary captures an error" 264 | }, 265 | "theme.common.skipToMainContent": { 266 | "message": "quack quack quack", 267 | "description": "The skip to content label used for accessibility, allowing to rapidly navigate to main content with keyboard tab/enter navigation" 268 | }, 269 | "theme.tags.tagsPageTitle": { 270 | "message": "quack", 271 | "description": "The title of the tag list page" 272 | } 273 | } 274 | -------------------------------------------------------------------------------- /Apps/docs/i18n/quack/docusaurus-plugin-content-docs/current.json: -------------------------------------------------------------------------------- 1 | { 2 | "version.label": { 3 | "message": "Quack", 4 | "description": "The label for version current" 5 | }, 6 | "sidebar.tutorialSidebar.category.Guide": { 7 | "message": "Quack", 8 | "description": "The label for category Guide in sidebar tutorialSidebar" 9 | }, 10 | "sidebar.tutorialSidebar.category.Reference": { 11 | "message": "Quack", 12 | "description": "The label for category Reference in sidebar tutorialSidebar" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Apps/docs/i18n/quack/docusaurus-plugin-content-docs/current/GetStarted.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 1 3 | slug: / 4 | --- 5 | 6 | # Quackscript 7 | 8 | :::danger Quack quack 9 | Quack quack quack quack quack quack quack **quack** quack 10 | ::: 11 | 12 | ## Quack quack 13 | 14 | Quack quack quack quack quackscript quack **[Quack quack](https://quackscript.com)**. 15 | -------------------------------------------------------------------------------- /Apps/docs/i18n/quack/docusaurus-plugin-content-docs/current/Guide/ControlFlow.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 3 3 | --- 4 | 5 | # Quack quack quack 6 | 7 | QuackScript quack quack quack quack quack quack quack quack quack quack quack quack quack quack quack. 8 | 9 | ## Quack If 10 | 11 | Quack quack if quack quack quack quack quack quack quack quack quack quack quack quack `true`. Quack quack quack quack quack quack `true` 12 | 13 | ```js 14 | if ( /* quack */ ) { 15 | // quack 16 | } 17 | ``` 18 | 19 | Quack quack quack quack quack `else` quack quack quack quack quack quack quack quack quack quack quack if quack falsa. 20 | 21 | ```js 22 | if ( /* quack */ ) { 23 | // quack quack quack quack quack quack quack quack 24 | } else { 25 | // quack quack quack quack quack quack quack quack 26 | } 27 | ``` -------------------------------------------------------------------------------- /Apps/docs/i18n/quack/docusaurus-plugin-content-docs/current/Guide/Functions.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 2 3 | --- 4 | 5 | # Quacks 6 | 7 | Quack quack quack quack quack quack quack quack quack quack quack quack quack. Quack quack quack quack quack quack quack quack quack quack quack quack quack quack quack. 8 | 9 | Quack quack quack Quackscript quack quack quack quack quack quack quack, quack quack quack quack quack, quack quack quack quack quack quack quack quack. 10 | 11 | 12 | ## Quack quack quack 13 | 14 | Quack quack quack quack quack QuackScript quack quack quack quack quack quack quack 0 quack quack quack. quack quack quack quack quack quack quack quack quack quack. 15 | 16 | ``` 17 | QUACK fnQuack <- () > { 18 | quackprint('Quack quack')🦆 19 | }🦆 20 | ``` 21 | 22 | ## Quack quack quack 23 | 24 | Quack quack quack quack quack `return` quack quack quack `nothing`. Quack `return` quack quack quack quack quack quack quack quack. 25 | 26 | ```js 27 | quack QuackQuack <- () > { 28 | return 'quack'🦆 29 | }🦆 30 | ``` 31 | 32 | ## Quacks 33 | 34 | Quack quack quack quack 0 quack quack quack. Quack quack quack quack quack quack quack quack quack quack quack quack quack. 35 | 36 | ```js 37 | quack quaack <- (quack1, quack2) > { 38 | return quack1 + quack2🦆 39 | }🦆 40 | 41 | 42 | quaack(1, 2)🦆 43 | ``` 44 | -------------------------------------------------------------------------------- /Apps/docs/i18n/quack/docusaurus-plugin-content-docs/current/Guide/GrammarAndTypes.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 1 3 | --- 4 | 5 | # Quack quack quack 6 | 7 | Quack quack quack quack quack quack, quack quack quack, quack quack quack quack quack quack quack quack QuackScript. 8 | 9 | ## Quack 10 | 11 | Quack QuackScript quack quack quack quack quack 🦆 12 | 13 | ## Quacks 14 | 15 | Quack quack quack QuackScript quack quack `//` quack quack quack quack quack quack quack. 16 | Quack quack quack quack quack quack quack, quack quack quack quack quack quack. Quack quack quack quack quack quack quack quack quack quack quack. 17 | 18 | ```js 19 | // quack quack quack quack 20 | ``` 21 | 22 | Quack quack quack quack quack quack quack `/*` quack quack quack `*/` 23 | 24 | ```js 25 | /* 26 | 27 | quack quack quack quack quack 28 | 29 | */ 30 | ``` 31 | 32 | ## Quack 33 | 34 | QuackScript quack quack quack quack quack quack. 35 | 36 | `quack` Quack quack quack. 37 | 38 | `QUACK` Quack quack quack quack quack quack quack quack quack quack quack. 39 | 40 | ### Quack quack quack 41 | 42 | Quack quack quack quack quack quack quack quack quack quack, quack quack quack quack quack quack quack. 43 | 44 | Quack quack `quack` quack `QUACK` quack quack quack quack quack quack quack. (Quack *quack quack quack* quack.) 45 | 46 | Quack quack quack quack quack quack quack quack quack: 47 | 48 | ```js 49 | quack a🦆 50 | ``` 51 | 52 | Quack quack quack quack quack quack quack quack quack quack quack quack quack quack quack: 53 | 54 | ```js 55 | quack a <- 'quack quack'🦆 56 | ``` 57 | 58 | Quack quack quack quack quack quack quack quack. 59 | ```js 60 | QUACK a <- 'quack quack'🦆 61 | ``` 62 | 63 | ### Quack quack quack 64 | 65 | Quack QuackScript quack quack quack quack quack quack quack quack quack quack quack. 66 | 67 | Quack quack quack quack quack quack quack quack quack `{` `}` 68 | 69 | ```js 70 | quack a <- 'quack quack'🦆 71 | 72 | QUACK b <- () { 73 | QUACK c <- 32🦆 74 | a <- 'quack quack'🦆 75 | }🦆 76 | ``` 77 | 78 | Quack quack quack quack quack quack `a` quack quack quack quack quack, quack quack quack quack quack quack quack quack quack. Quack quack `c` quack quack quack quack quack quack quack quack, quack quack quack quack quack quack quack quack quack quack quack quack. Quack quack quack quack quack quack quack quack quack quack quack quack quack quack quack quack quack, quack quack quack quack quack quack quack quack `b` quack quack `c` quack quack quack quack quack quack `a` quack quack quack quack `'adiós mundo'`. 79 | 80 | ## Quack quack 81 | 82 | Quackscript quack quack quack quack quack: 83 | 84 | 1. `boolean` - `true` quack `false`. 85 | 1. `nothing` - Quack quack quack quack quack quack quack quack quack quack. Quack quack quack quack quack `nothing` quack quack quack quack quack quack quack quack `nothing` 86 | 1. `number` - Quack quack quack quack quack quack quack. Quack `32` quack `32.5` 87 | 1. `text` - Quack quack quack quack quack. Quack `'Quack Quack'` 88 | 1. `function` - Quack quack quack quack quack. 89 | 1. `object` - *[quack quack]* 90 | 1. `list` - *[quack quack]* Quack quack quack quack quack quack quack quack quack 91 | 1. `vector2` - *[quack quack]* Quack quack quack 2 quack quack quack `x` quack `y` `quack` quack 92 | 1. `vector3` - *[quack quack]* Quack quack quack 3 quack quack quack `x`, `y` quack `z` `quack` quack 93 | 1. `dictionary` - *[quack quack]* Quack quack quack quack quack quack quack quack quack quack quack quack quack quack quack quack 94 | 95 | ### Quack 96 | 97 | Quack quack quack quack quack quack quack quack quack. Quack quack quack quack quack quack quack quack quack quack quack quack QuackScript quack quack quack quack quack quack. 98 | 99 | ```js 100 | QUACK a:text <- 'quack quack'🦆 101 | 102 | // quack quack quack quack quack quack quack quack quack quack quack quack 103 | // QuackScript quack quack quack quack quack quack quack 104 | QUACK b <- 'quack quack'🦆 105 | ``` 106 | 107 | QuackScript quack quack quack quack quack quack quack quack quack quack quack quack quack quack quack quack quack quack quack quack quack quack quack quack quack quack quack quack quack quack. 108 | 109 | ```js 110 | quack a:text <- 'quack quack'🦆 111 | 112 | // Quack quack quack quack quack quack 113 | a <- 23🦆 114 | ``` 115 | 116 | Quack quack quack quack quack quack quack quack quack quack quack quack quack quack quack `nothing`. Quack quack quack quack quack quack quack quack `?` quack quack quack quack quack quack. 117 | ```js 118 | quack quackQuackNothing?:string🦆 119 | // Quack quack quack 'quackQuackNothing' quack 'nothing' 120 | 121 | quackQuackNothing <- 'quack quack'🦆 122 | // Quack quack quack 'quackQuackNothing' quack 'quack quack' 123 | ``` -------------------------------------------------------------------------------- /Apps/docs/i18n/quack/docusaurus-theme-classic/footer.json: -------------------------------------------------------------------------------- 1 | { 2 | "link.title.Docs": { 3 | "message": "Quack", 4 | "description": "The title of the footer links column with title=Docs in the footer" 5 | }, 6 | "link.title.Community": { 7 | "message": "Quack", 8 | "description": "The title of the footer links column with title=Community in the footer" 9 | }, 10 | "link.title.More": { 11 | "message": "Quack", 12 | "description": "The title of the footer links column with title=More in the footer" 13 | }, 14 | "link.item.label.Get Started": { 15 | "message": "Quack Quack", 16 | "description": "The label of footer link with label=Get Started linking to /docs/intro" 17 | }, 18 | "link.item.label.Stack Overflow": { 19 | "message": "Quack Overflow", 20 | "description": "The label of footer link with label=Stack Overflow linking to https://stackoverflow.com/questions/tagged/quackscript" 21 | }, 22 | "link.item.label.Twitter": { 23 | "message": "Quacker", 24 | "description": "The label of footer link with label=Twitter linking to https://twitter.com/quackscript" 25 | }, 26 | "link.item.label.GitHub": { 27 | "message": "QuackHub", 28 | "description": "The label of footer link with label=GitHub linking to https://github.com/niv3k-el-pato/quackscript" 29 | }, 30 | "copyright": { 31 | "message": "Copyright © 2023 QuackScript", 32 | "description": "The footer copyright" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Apps/docs/i18n/quack/docusaurus-theme-classic/navbar.json: -------------------------------------------------------------------------------- 1 | { 2 | "logo.alt": { 3 | "message": "quack quack quack", 4 | "description": "The alt text of navbar logo" 5 | }, 6 | "item.label.GitHub": { 7 | "message": "quack", 8 | "description": "Navbar item with label GitHub" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Apps/docs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "docs", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "docusaurus": "docusaurus", 7 | "start": "docusaurus start", 8 | "build": "docusaurus build", 9 | "swizzle": "docusaurus swizzle", 10 | "deploy": "docusaurus deploy", 11 | "clear": "docusaurus clear", 12 | "serve": "docusaurus serve", 13 | "write-translations": "docusaurus write-translations", 14 | "write-heading-ids": "docusaurus write-heading-ids", 15 | "typecheck": "tsc" 16 | }, 17 | "dependencies": { 18 | "@docusaurus/core": "2.4.0", 19 | "@docusaurus/preset-classic": "2.4.0", 20 | "@mdx-js/react": "^1.6.22", 21 | "clsx": "^1.2.1", 22 | "prism-react-renderer": "^1.3.5", 23 | "react": "^17.0.2", 24 | "react-dom": "^17.0.2" 25 | }, 26 | "devDependencies": { 27 | "@docusaurus/module-type-aliases": "2.4.0", 28 | "@tsconfig/docusaurus": "^1.0.5", 29 | "typescript": "^4.7.4" 30 | }, 31 | "browserslist": { 32 | "production": [ 33 | ">0.5%", 34 | "not dead", 35 | "not op_mini all" 36 | ], 37 | "development": [ 38 | "last 1 chrome version", 39 | "last 1 firefox version", 40 | "last 1 safari version" 41 | ] 42 | }, 43 | "engines": { 44 | "node": ">=16.14" 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /Apps/docs/sidebars.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Creating a sidebar enables you to: 3 | - create an ordered group of docs 4 | - render a sidebar for each doc of that group 5 | - provide next/previous navigation 6 | 7 | The sidebars can be generated from the filesystem, or explicitly defined here. 8 | 9 | Create as many sidebars as you want. 10 | */ 11 | 12 | // @ts-check 13 | 14 | /** @type {import('@docusaurus/plugin-content-docs').SidebarsConfig} */ 15 | const sidebars = { 16 | // By default, Docusaurus generates a sidebar from the docs folder structure 17 | tutorialSidebar: [{type: 'autogenerated', dirName: '.'}], 18 | 19 | // But you can create a sidebar manually 20 | /* 21 | tutorialSidebar: [ 22 | 'intro', 23 | 'hello', 24 | { 25 | type: 'category', 26 | label: 'Tutorial', 27 | items: ['tutorial-basics/create-a-document'], 28 | }, 29 | ], 30 | */ 31 | }; 32 | 33 | module.exports = sidebars; 34 | -------------------------------------------------------------------------------- /Apps/docs/static/.nojekyll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PatitoDev/QuackScript/53454c0dd70f220b0eab8f1b2a267a15685a8751/Apps/docs/static/.nojekyll -------------------------------------------------------------------------------- /Apps/docs/static/img/QuackScriptLogoHorizontal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PatitoDev/QuackScript/53454c0dd70f220b0eab8f1b2a267a15685a8751/Apps/docs/static/img/QuackScriptLogoHorizontal.png -------------------------------------------------------------------------------- /Apps/docs/static/img/docusaurus-social-card.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PatitoDev/QuackScript/53454c0dd70f220b0eab8f1b2a267a15685a8751/Apps/docs/static/img/docusaurus-social-card.jpg -------------------------------------------------------------------------------- /Apps/docs/static/img/docusaurus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PatitoDev/QuackScript/53454c0dd70f220b0eab8f1b2a267a15685a8751/Apps/docs/static/img/docusaurus.png -------------------------------------------------------------------------------- /Apps/docs/static/img/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PatitoDev/QuackScript/53454c0dd70f220b0eab8f1b2a267a15685a8751/Apps/docs/static/img/favicon.ico -------------------------------------------------------------------------------- /Apps/docs/static/img/logo.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Apps/docs/static/img/undraw_docusaurus_tree.svg: -------------------------------------------------------------------------------- 1 | 2 | Focus on What Matters 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /Apps/docs/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | // This file is not used in compilation. It is here just for a nice editor experience. 3 | "extends": "@tsconfig/docusaurus/tsconfig.json", 4 | "compilerOptions": { 5 | "baseUrl": "." 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /Apps/web/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "browser": true, 4 | "es2021": true 5 | }, 6 | "extends": [ 7 | "eslint:recommended", 8 | "plugin:react/recommended", 9 | "plugin:@typescript-eslint/recommended", 10 | "plugin:react/jsx-runtime" 11 | ], 12 | "overrides": [ 13 | ], 14 | "parser": "@typescript-eslint/parser", 15 | "parserOptions": { 16 | "ecmaVersion": "latest", 17 | "sourceType": "module" 18 | }, 19 | "plugins": [ 20 | "react", 21 | "@typescript-eslint" 22 | ], 23 | "rules": { 24 | "indent": [ 25 | "error", 26 | 4 27 | ], 28 | "linebreak-style": [ 29 | "error", 30 | "unix" 31 | ], 32 | "quotes": [ 33 | "error", 34 | "single" 35 | ], 36 | "semi": [ 37 | "error", 38 | "always" 39 | ] 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Apps/web/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /Apps/web/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | QuackScript - The JS killer 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /Apps/web/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "quackscript-ui", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "test": "jest", 9 | "build": "tsc && vite build", 10 | "preview": "vite preview" 11 | }, 12 | "dependencies": { 13 | "@monaco-editor/react": "^4.4.6", 14 | "@types/styled-components": "^5.1.26", 15 | "react": "^18.2.0", 16 | "react-dom": "^18.2.0", 17 | "react-icons": "^4.8.0", 18 | "styled-components": "^5.3.9", 19 | "quackscript": "*" 20 | }, 21 | "devDependencies": { 22 | "@types/react": "^18.0.27", 23 | "@types/react-dom": "^18.0.10", 24 | "@typescript-eslint/eslint-plugin": "^5.55.0", 25 | "@typescript-eslint/parser": "^5.55.0", 26 | "@vitejs/plugin-react-swc": "^3.0.0", 27 | "eslint": "^8.36.0", 28 | "eslint-plugin-react": "^7.32.2", 29 | "typescript": "^4.9.3", 30 | "vite": "^4.1.0" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Apps/web/public/img/AvatarSimpleMd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PatitoDev/QuackScript/53454c0dd70f220b0eab8f1b2a267a15685a8751/Apps/web/public/img/AvatarSimpleMd.png -------------------------------------------------------------------------------- /Apps/web/public/img/DrOctopus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PatitoDev/QuackScript/53454c0dd70f220b0eab8f1b2a267a15685a8751/Apps/web/public/img/DrOctopus.png -------------------------------------------------------------------------------- /Apps/web/public/img/DuckAvatarMd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PatitoDev/QuackScript/53454c0dd70f220b0eab8f1b2a267a15685a8751/Apps/web/public/img/DuckAvatarMd.png -------------------------------------------------------------------------------- /Apps/web/public/img/QuackScriptLogoHorizontal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PatitoDev/QuackScript/53454c0dd70f220b0eab8f1b2a267a15685a8751/Apps/web/public/img/QuackScriptLogoHorizontal.png -------------------------------------------------------------------------------- /Apps/web/public/img/QuackScriptLogoHorizontalSm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PatitoDev/QuackScript/53454c0dd70f220b0eab8f1b2a267a15685a8751/Apps/web/public/img/QuackScriptLogoHorizontalSm.png -------------------------------------------------------------------------------- /Apps/web/public/vite.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Apps/web/src/App.tsx: -------------------------------------------------------------------------------- 1 | import { createGlobalStyle } from 'styled-components'; 2 | import Header from './components/organism/Header'; 3 | import Home from './components/pages/Home'; 4 | 5 | const GlobalStyle = createGlobalStyle` 6 | html, body { 7 | min-height: 100vh; 8 | background-color: ${({ theme }) => theme.colors.white}; 9 | } 10 | `; 11 | 12 | function App() { 13 | return ( 14 | <> 15 | 16 |
17 | 18 | 19 | ); 20 | } 21 | 22 | export default App; 23 | -------------------------------------------------------------------------------- /Apps/web/src/assets/react.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Apps/web/src/commonTheme/theme.ts: -------------------------------------------------------------------------------- 1 | import { DefaultTheme } from 'styled-components'; 2 | 3 | export const theme: DefaultTheme = { 4 | colors: { 5 | black: '#1B1A1D', 6 | gray: '#999999', 7 | primary: '#FFD953', 8 | white: '#E4E4E4', 9 | darkGray: '#313034', 10 | }, 11 | media: { 12 | mobile: 'max-width: 800px', 13 | }, 14 | sizes: { 15 | desktopMaxWidth: '1500px', 16 | } 17 | }; -------------------------------------------------------------------------------- /Apps/web/src/components/atoms/Button/index.tsx: -------------------------------------------------------------------------------- 1 | import styled, { css } from 'styled-components'; 2 | 3 | export type ButtonVariant = 'solid' | 'outline'; 4 | 5 | const Button = styled.button<{ 6 | size?: 'sm' | 'md' 7 | variant?: ButtonVariant, 8 | mobileOnly?: boolean 9 | }>` 10 | ${({ mobileOnly }) => mobileOnly && css` 11 | @media screen and not (${({ theme }) => theme.media.mobile}) { 12 | display: none; 13 | } 14 | `} 15 | 16 | @media screen and (${({ theme }) => theme.media.mobile}) { 17 | padding: ${({ size = 'md' }) => size === 'md' ? '1em' : '0.5em'}; 18 | font-size: 1em; 19 | } 20 | 21 | display: flex; 22 | align-items: center; 23 | justify-content: center; 24 | cursor: pointer; 25 | border: none; 26 | border-radius: 5px; 27 | padding: 16px 26px; 28 | font-size: 20px; 29 | font-weight: bold; 30 | 31 | ${({ variant = 'solid', theme }) => variant === 'outline' && css` 32 | box-shadow: inset 0 0 0 4px ${theme.colors.primary}; 33 | @media screen and (${({ theme }) => theme.media.mobile}) { 34 | box-shadow: inset 0 0 0 2px ${theme.colors.primary}; 35 | } 36 | color: ${theme.colors.primary}; 37 | background-color: transparent; 38 | :hover { 39 | background-color: ${theme.colors.primary}; 40 | color: ${theme.colors.black}; 41 | } 42 | `} 43 | 44 | ${({ variant = 'solid', theme }) => variant === 'solid' && css` 45 | color: ${theme.colors.black}; 46 | background-color: ${theme.colors.primary}; 47 | `} 48 | 49 | :focus-within { 50 | outline: 3px ${({ theme }) => theme.colors.gray } solid 51 | } 52 | `; 53 | 54 | export default Button; -------------------------------------------------------------------------------- /Apps/web/src/components/atoms/Link/index.tsx: -------------------------------------------------------------------------------- 1 | import styled, { css } from 'styled-components'; 2 | 3 | const Link = styled.a<{ 4 | selected?: boolean 5 | }>` 6 | cursor: pointer; 7 | color: ${({ theme }) => theme.colors.white}; 8 | font-weight: bold; 9 | font-size: 18px; 10 | text-decoration: none; 11 | 12 | ${({ selected = false, theme }) => selected && css` 13 | box-shadow: ${theme.colors.primary} 0 5px 0px; 14 | `} 15 | 16 | :hover { 17 | box-shadow: ${({ theme }) => theme.colors.primary} 0 5px 0px; 18 | color: ${({ theme }) => theme.colors.white}; 19 | } 20 | `; 21 | 22 | export default Link; -------------------------------------------------------------------------------- /Apps/web/src/components/atoms/Typography/index.tsx: -------------------------------------------------------------------------------- 1 | import Styled, { css, DefaultTheme } from 'styled-components'; 2 | 3 | export type TypographyVariant = 'title' | 'heading' | 'body' | 'info'; 4 | 5 | const Typography = Styled.span<{ 6 | variant?: TypographyVariant, 7 | textColor?: keyof DefaultTheme['colors'], 8 | weight?: 'bold' | 'normal', 9 | block?: boolean, 10 | mb?: string, 11 | }>` 12 | font-family: Poppins; 13 | 14 | ${({ mb }) => mb && css` 15 | margin-bottom: ${mb}; 16 | `} 17 | 18 | ${({ block }) => block && css` 19 | display: block; 20 | `} 21 | 22 | ${({ theme, textColor = 'white' }) => css` 23 | color: ${theme.colors[textColor]}; 24 | `} 25 | 26 | ${({ variant = 'body' }) => variant === 'title' && css` 27 | font-size: 42px; 28 | font-weight: bold; 29 | `} 30 | 31 | ${({ variant = 'body' }) => variant === 'heading' && css` 32 | font-size: 32px; 33 | font-weight: bold; 34 | `} 35 | 36 | ${({ variant = 'body' }) => variant === 'body' && css` 37 | font-size: 18px; 38 | `} 39 | 40 | ${({ variant = 'body' }) => variant === 'info' && css` 41 | font-size: 14px; 42 | `} 43 | 44 | ${({ weight }) => weight && css` 45 | font-weight: ${weight}; 46 | `} 47 | `; 48 | 49 | export default Typography; -------------------------------------------------------------------------------- /Apps/web/src/components/molecules/CodeEditor/index.tsx: -------------------------------------------------------------------------------- 1 | import Editor, { EditorProps } from '@monaco-editor/react'; 2 | import { useMonaco } from '@monaco-editor/react'; 3 | import { useEffect } from 'react'; 4 | import { useTheme } from 'styled-components'; 5 | import './style.css'; 6 | 7 | const EDITOR_OPTIONS = { 8 | fontSize: 18, 9 | automaticLayout: true, 10 | lineNumbersMinChars: 2, 11 | minimap: { 12 | enabled: false 13 | }, 14 | scrollbar: { 15 | verticalScrollbarSize: 3, 16 | horizontalScrollbarSize: 3 17 | }, 18 | lineDecorationsWidth: 0, 19 | }; 20 | 21 | interface Word { 22 | startColumn: number, 23 | endColumn: number, 24 | } 25 | 26 | interface Model { 27 | getWordUntilPosition: (position:Position) => Word, 28 | } 29 | 30 | interface Position { 31 | lineNumber: number, 32 | startColumn: number, 33 | } 34 | 35 | const CodeEditor = (props: EditorProps) => { 36 | 37 | const monaco = useMonaco(); 38 | const theme = useTheme(); 39 | 40 | useEffect(() => { 41 | if (monaco) { 42 | const hasLanguage = (monaco.languages.getLanguages().find((lang: {id: string}) => lang.id === 'quackscript' )); 43 | if (!hasLanguage) { 44 | monaco.languages.register({ id: 'quackscript' }); 45 | monaco.languages.setMonarchTokensProvider('quackscript', { 46 | tokenizer: { 47 | root: [ 48 | [/:[a-zA-Z]+/, 'keyword'], 49 | [/return /, 'keyword'], 50 | [/quack /, 'keyword'], 51 | [/QUACK /, 'keyword'], 52 | [/[^\s]+?(?=\()/, 'entity.name.function'], 53 | [/\(/, 'delimiter.bracket'], 54 | [/\)/, 'delimiter.bracket'], 55 | [/'.*?'/, 'string'], 56 | [/<-/, 'delimiter'], 57 | [//, 'delimiter'], 59 | [/{/, 'delimiter'], 60 | [/}/, 'delimiter'], 61 | [/\)/, 'delimiter'], 62 | [/\(/, 'delimiter'], 63 | [/[0-9]/, 'number'], 64 | [/[a-zA-Z][a-zA-Z0-9_]*/, 'identifier'] 65 | ], 66 | }, 67 | }); 68 | 69 | monaco.editor.defineTheme('quackscript-theme', { 70 | base: 'vs', 71 | inherit: true, 72 | rules: [ 73 | { token: 'keyword', foreground: '#7B20D7' }, 74 | { token: 'delimiter', foreground: '#251ccc8d' }, 75 | { token: 'entity.name.function', foreground: '#251ccc8d', fontStyle: 'bold' }, 76 | ], 77 | colors: { 78 | 'editor.foreground': theme.colors.black, 79 | 'editor.background': theme.colors.white, 80 | 'editorCursor.foreground': theme.colors.black, 81 | 'editor.lineHighlightBackground': '#3f3f3f15', 82 | 'editorLineNumber.foreground': theme.colors.black, 83 | 'editor.selectionBackground': '#3f3f3f15', 84 | 'editor.inactiveSelectionBackground': '#3f3f3f15', 85 | }, 86 | }); 87 | monaco.languages.registerCompletionItemProvider('quackscript', { 88 | provideCompletionItems: (model: Model, position:Position ) => { 89 | const word = model.getWordUntilPosition(position); 90 | const range = { 91 | startLineNumber: position.lineNumber, 92 | endLineNumber: position.lineNumber, 93 | startColumn: word.startColumn, 94 | endColumn: word.endColumn, 95 | }; 96 | const suggestions = [ 97 | { 98 | label: 'quack - variable', 99 | kind: monaco.languages.CompletionItemKind.Text, 100 | insertText: 'quack', 101 | range: range, 102 | }, 103 | { 104 | label: 'QUACK - constant', 105 | kind: monaco.languages.CompletionItemKind.Text, 106 | insertText: 'quack', 107 | range: range, 108 | }, 109 | { 110 | label: 'when', 111 | kind: monaco.languages.CompletionItemKind.Text, 112 | insertText: 'when', 113 | range: range, 114 | }, 115 | { 116 | label: 'quackprint', 117 | kind: monaco.languages.CompletionItemKind.Text, 118 | insertText: 'quackprint', 119 | range: range, 120 | }, 121 | ]; 122 | return { suggestions: suggestions }; 123 | }, 124 | }); 125 | } 126 | monaco.editor.setTheme('quackscript-theme'); 127 | } 128 | }, [monaco]); 129 | 130 | return ( 131 | 137 | ); 138 | 139 | }; 140 | 141 | export default CodeEditor; -------------------------------------------------------------------------------- /Apps/web/src/components/molecules/CodeEditor/style.css: -------------------------------------------------------------------------------- 1 | .editor { 2 | border-radius: 3px; 3 | padding: 0.5em; 4 | background-color: rgb(228, 228, 228); 5 | } -------------------------------------------------------------------------------- /Apps/web/src/components/organism/Header/index.tsx: -------------------------------------------------------------------------------- 1 | import { BiMenu } from 'react-icons/all'; 2 | import Link from '../../atoms/Link'; 3 | import * as S from './style'; 4 | import Button from '../../atoms/Button'; 5 | import { useEffect, useState } from 'react'; 6 | import { createGlobalStyle, useTheme } from 'styled-components'; 7 | 8 | const routes: Array<{ 9 | displayName: React.ReactNode, 10 | route: string 11 | }> = [ 12 | { displayName: 'Home', route: '/' }, 13 | { displayName: 'Docs', route: '/docs' }, 14 | { displayName: 'Github', route: 'https://github.com/niv3k-el-pato/quackscript' }, 15 | ]; 16 | 17 | const OverflowDisabled = createGlobalStyle` 18 | html { 19 | overflow: hidden; 20 | } 21 | `; 22 | 23 | const Header = () => { 24 | const theme = useTheme(); 25 | const [ isMobileMenuOpen, setIsMobileMenuOpen ] = useState(false); 26 | 27 | useEffect(() => { 28 | if (!isMobileMenuOpen) return; 29 | window.scrollTo({ 30 | behavior: 'smooth', 31 | top: 0 32 | }); 33 | }, [isMobileMenuOpen]); 34 | 35 | return ( 36 | 37 | { isMobileMenuOpen && } 38 | 39 | 40 | 41 | 42 | 43 | 46 | 47 | { 48 | routes.map((route) => ( 49 | 50 | {route.displayName} 51 | 52 | )) 53 | } 54 | 55 | 56 | 57 | { 58 | routes.map((route) => ( 59 | 60 | 61 | {route.displayName} 62 | 63 | 64 | )) 65 | } 66 | 67 | 68 | ); 69 | }; 70 | 71 | export default Header; -------------------------------------------------------------------------------- /Apps/web/src/components/organism/Header/style.ts: -------------------------------------------------------------------------------- 1 | import styled, { css } from 'styled-components'; 2 | 3 | export const Container = styled.header` 4 | background-color: ${({ theme }) => theme.colors.black}; 5 | color: ${({ theme }) => theme.colors.white}; 6 | padding: 2em 3em; 7 | border-bottom: 1px solid ${({ theme }) => theme.colors.darkGray}; 8 | @media screen and (${({ theme }) => theme.media.mobile}) { 9 | padding: 1em 1.2em; 10 | } 11 | `; 12 | 13 | export const BoundsCountainer = styled.div` 14 | margin: auto; 15 | max-width: ${({ theme }) => theme.sizes.desktopMaxWidth}; 16 | display: flex; 17 | align-items: center; 18 | justify-content: space-between; 19 | `; 20 | 21 | export const NavigationContainer = styled.nav` 22 | display: flex; 23 | align-items: center; 24 | > * { 25 | margin: 0.5em; 26 | } 27 | @media screen and (${({ theme }) => theme.media.mobile}) { 28 | display: none; 29 | } 30 | `; 31 | 32 | export const NavImage = styled.img` 33 | width: 200px; 34 | @media screen and (${({ theme }) => theme.media.mobile}) { 35 | width: 60px; 36 | } 37 | `; 38 | 39 | export const MobileMenu = styled.div<{ 40 | isOpen?: boolean 41 | }>` 42 | @media screen and not (${({ theme }) => theme.media.mobile}) { 43 | display: none; 44 | } 45 | 46 | overflow: auto; 47 | z-index: 99; 48 | background-color: ${({ theme }) => theme.colors.black }; 49 | width: 100vw; 50 | height: calc(100vh - 81px); 51 | bottom: 0; 52 | display: flex; 53 | flex-direction: column; 54 | align-items: center; 55 | position: fixed; 56 | 57 | transition: left 0.5s ease-in-out; 58 | left: 101vw; 59 | 60 | ${({ isOpen }) => isOpen && css` 61 | left: 0; 62 | `} 63 | `; 64 | 65 | export const MobileMenuLink = styled.a<{ 66 | selected?: boolean 67 | }>` 68 | text-align: center; 69 | width: 100vw; 70 | padding: 2em; 71 | margin: 1em 0; 72 | 73 | cursor: pointer; 74 | color: ${({ theme }) => theme.colors.white}; 75 | font-weight: bold; 76 | font-size: 18px; 77 | text-decoration: none; 78 | 79 | ${({ selected = false, theme }) => selected && css` 80 | > span { 81 | box-shadow: ${theme.colors.primary} 0 5px 0px; 82 | } 83 | `} 84 | 85 | :hover > span { 86 | box-shadow: ${({ theme }) => theme.colors.primary} 0 5px 0px; 87 | color: ${({ theme }) => theme.colors.white}; 88 | } 89 | `; -------------------------------------------------------------------------------- /Apps/web/src/components/organism/QuackScriptEditor/index.tsx: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from 'react'; 2 | import CodeEditor from '../../molecules/CodeEditor'; 3 | import * as S from './style'; 4 | // TODO - import npm package 5 | import { Interpreter, Lexer, Parser } from 'quackscript'; 6 | 7 | const defaultQuackTextValue = `QUACK exampleFunction <- (value:text) > { 8 | return value🦆 9 | }🦆 10 | 11 | quack optionalVariableTest?:text🦆 12 | optionalVariableTest <- 'hello world'🦆 13 | 14 | exampleFunction('this is quackscript')🦆 15 | exampleFunction('in action')🦆 16 | 17 | QUACK add <- ( first:number, second:number ) > { 18 | return first + second🦆 19 | }🦆 20 | 21 | add(5, 8)🦆 22 | quackprint(optionalVariableTest.unwrap())🦆 23 | `; 24 | 25 | 26 | const loadFile = (value: string) => { 27 | if (value === './index.quack'){ 28 | return 'QUACK add <- (:a,b:) :> {:return a + b🦆:}🦆'; 29 | } 30 | throw new Error('file not found'); 31 | }; 32 | 33 | const lexer = new Lexer(); 34 | const parser = new Parser(); 35 | 36 | const QuackScriptEditor = () => { 37 | const [quackCode, setQuackCode] = useState(defaultQuackTextValue); 38 | const [codeOutcome, setCodeOutcome] = useState(''); 39 | const [interpreter, setInterpreter] = useState(new Interpreter()); 40 | 41 | const onQuackCodeChange = (value:string | undefined) => { 42 | const valueWithoutSemicolons = value?.replaceAll(';', '🦆'); 43 | 44 | setQuackCode(valueWithoutSemicolons ?? ''); 45 | }; 46 | 47 | useEffect(() => { 48 | const handleOutput = (value:string) => { 49 | setCodeOutcome((pre) => { 50 | return pre.length ? pre + '\n' + `${value}` : `${value}`; 51 | }); 52 | }; 53 | 54 | setInterpreter(new Interpreter(handleOutput, handleOutput, loadFile)); 55 | }, []); 56 | 57 | useEffect(() => { 58 | try { 59 | setCodeOutcome(''); 60 | const tokens = lexer.convertToTokens(quackCode); 61 | const parsedOutcome = parser.parse(tokens); 62 | console.log('tree: ', [...parsedOutcome.statements]); 63 | interpreter.execute(parsedOutcome, quackCode); 64 | } catch (e) { 65 | console.error(e); 66 | setCodeOutcome((e as Error).message); 67 | } 68 | }, [quackCode, interpreter]); 69 | 70 | return ( 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 83 | 88 | 89 | 90 | ); 91 | }; 92 | 93 | export default QuackScriptEditor; -------------------------------------------------------------------------------- /Apps/web/src/components/organism/QuackScriptEditor/style.ts: -------------------------------------------------------------------------------- 1 | import styled, { css } from 'styled-components'; 2 | 3 | export const Container = styled.div` 4 | margin-top: 1em; 5 | background-color: ${({ theme }) => theme.colors.black}; 6 | padding: 0 1.5em 1.5em 1.5em; 7 | border-radius: 10px; 8 | max-width: 100%; 9 | 10 | @media screen and (${({ theme }) => theme.media.mobile}) { 11 | padding: 0.5em; 12 | } 13 | `; 14 | 15 | export const CodeWindowContent = styled.div` 16 | max-width: 100%; 17 | > * { 18 | // code editor 19 | border-radius: 5px; 20 | //overflow: hidden; 21 | } 22 | > :last-child { 23 | margin-top: 1em; 24 | } 25 | `; 26 | 27 | export const CodeWindowHeader = styled.div` 28 | width: 100%; 29 | padding: 1.5em 1em; 30 | display: flex; 31 | gap: 0.5em; 32 | @media screen and (${({ theme }) => theme.media.mobile}) { 33 | padding: 0.8em 0.5em; 34 | } 35 | `; 36 | 37 | export const Divider = styled.div` 38 | display: flex; 39 | align-items: center; 40 | justify-content: center; 41 | cursor: pointer; 42 | min-width: 2em; 43 | background-color: ${({ theme }) => theme.colors.black}; 44 | `; 45 | 46 | export const WindowActionButton = styled.div<{ 47 | variant: 'red' | 'yellow' | 'green' 48 | }>` 49 | border-radius: 50%; 50 | width: 1em; 51 | height: 1em; 52 | ${({ variant = 'red' }) => variant === 'red' && css` 53 | background-color: #DF4949; 54 | `} 55 | 56 | ${({ variant = 'red' }) => variant === 'yellow' && css` 57 | background-color: #FFED4F; 58 | `} 59 | 60 | ${({ variant = 'red' }) => variant === 'green' && css` 61 | background-color: #5BD876; 62 | `} 63 | `; -------------------------------------------------------------------------------- /Apps/web/src/components/pages/Home/index.tsx: -------------------------------------------------------------------------------- 1 | import CodeSection from '../HomeSections/CodeSection'; 2 | import MainHome from '../HomeSections/Main'; 3 | 4 | const Home = () => ( 5 | <> 6 | 7 | 8 | 9 | ); 10 | 11 | export default Home; -------------------------------------------------------------------------------- /Apps/web/src/components/pages/HomeSections/CodeSection/index.tsx: -------------------------------------------------------------------------------- 1 | import Typography from '../../../atoms/Typography'; 2 | import QuackScriptEditor from '../../../organism/QuackScriptEditor'; 3 | import Section from '../../../template/Section'; 4 | import * as S from './style'; 5 | 6 | const CodeSection = () => ( 7 |
8 | 9 |
10 | 11 | The power of JS in the palm of your hand 12 | 13 | 14 | QuackScript compiles to native JS, providing you the fastest code possible 15 | 16 |
17 | 18 |
19 |
20 | ); 21 | 22 | export default CodeSection; -------------------------------------------------------------------------------- /Apps/web/src/components/pages/HomeSections/CodeSection/style.ts: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components'; 2 | import { CenterSectionContainer } from '../../../template/CenterSectionContainer'; 3 | 4 | export const CodeSectionContainer = styled(CenterSectionContainer)` 5 | flex-direction: column; 6 | padding-left: 0; 7 | padding-right: 0; 8 | 9 | > * { 10 | margin: 0 0.8em; 11 | } 12 | 13 | > :first-child { 14 | margin: 0 2em; 15 | } 16 | `; -------------------------------------------------------------------------------- /Apps/web/src/components/pages/HomeSections/CompaniesSection/index.tsx: -------------------------------------------------------------------------------- 1 | import Typography from '../../../atoms/Typography'; 2 | import Section from '../../../template/Section'; 3 | 4 | const CompaniesSection = () => ( 5 |
6 | 7 | Companies using QuackScript 8 | 9 |
10 | ); 11 | 12 | export default CompaniesSection; -------------------------------------------------------------------------------- /Apps/web/src/components/pages/HomeSections/GameDemoSection/index.tsx: -------------------------------------------------------------------------------- 1 | import Typography from '../../../atoms/Typography'; 2 | import Section from '../../../template/Section'; 3 | 4 | const GameDemoSection = () => ( 5 |
6 | 7 | Build powerful 2D games 8 | 9 |
10 | ); 11 | 12 | export default GameDemoSection; -------------------------------------------------------------------------------- /Apps/web/src/components/pages/HomeSections/Main/index.tsx: -------------------------------------------------------------------------------- 1 | import Button from '../../../atoms/Button'; 2 | import Typography from '../../../atoms/Typography'; 3 | import * as S from './style'; 4 | import Duck from '../../../atoms/Duck'; 5 | import { CenterSectionContainer } from '../../../template/CenterSectionContainer'; 6 | 7 | const MainHome = () => ( 8 | 9 | 10 | 11 | QuackScript 15 | the most quackstastic language ever created 18 | Created by ducks for ducks 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | ); 30 | 31 | export default MainHome; -------------------------------------------------------------------------------- /Apps/web/src/components/pages/HomeSections/Main/style.ts: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components'; 2 | import Button from '../../../atoms/Button'; 3 | import Section from '../../../template/Section'; 4 | 5 | export const MainContainer = styled(Section)` 6 | position: relative; 7 | justify-content: center; 8 | max-height: 700px; 9 | overflow: hidden; 10 | @media screen and (${({ theme }) => theme.media.mobile}) { 11 | padding: 3em 2em; 12 | } 13 | `; 14 | 15 | export const Container = styled.div` 16 | display: flex; 17 | flex-direction: column; 18 | align-items: flex-start; 19 | > * { 20 | margin-bottom: 0.5rem; 21 | } 22 | > ${Button} { 23 | margin-top: 5em; 24 | } 25 | `; 26 | 27 | export const Image = styled.div` 28 | transition: left 0.5s ease-in-out; 29 | position: relative; 30 | left: 0; 31 | bottom: 0; 32 | width: 791px; 33 | height: 507px; 34 | > img { 35 | min-width: 1068px; 36 | min-height: 1040px; 37 | aspect-ratio: 1 / 1; 38 | } 39 | @media screen and (${({ theme }) => theme.media.mobile}) { 40 | bottom: 0; 41 | position: absolute; 42 | left: calc(100vw - 249px); 43 | height: 438px; 44 | > svg { 45 | width: 26em; 46 | } 47 | } 48 | `; -------------------------------------------------------------------------------- /Apps/web/src/components/pages/HomeSections/PlatformSection/index.tsx: -------------------------------------------------------------------------------- 1 | import Typography from '../../../atoms/Typography'; 2 | import Section from '../../../template/Section'; 3 | 4 | const PlatformSection = () => ( 5 |
6 | 7 | Web 8 | 9 |
10 | ); 11 | 12 | export default PlatformSection; -------------------------------------------------------------------------------- /Apps/web/src/components/pages/HomeSections/StatsSection/index.tsx: -------------------------------------------------------------------------------- 1 | import Typography from '../../../atoms/Typography'; 2 | import Section from '../../../template/Section'; 3 | 4 | const StatsSection = () => ( 5 |
6 | 7 | The numbers speak for themselves 8 | 9 |
10 | ); 11 | 12 | export default StatsSection; -------------------------------------------------------------------------------- /Apps/web/src/components/template/CenterSectionContainer/index.tsx: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components'; 2 | 3 | 4 | export const CenterSectionContainer = styled.div` 5 | display: flex; 6 | flex-direction: row; 7 | max-width: ${({ theme }) => theme.sizes.desktopMaxWidth}; 8 | width: 100%; 9 | margin: auto; 10 | 11 | @media screen and (${({ theme }) => theme.media.mobile}) { 12 | max-width: 100%; 13 | } 14 | 15 | @media screen and not (${({ theme }) => theme.media.mobile}) { 16 | padding: 0 2em; 17 | } 18 | `; -------------------------------------------------------------------------------- /Apps/web/src/components/template/Section/index.tsx: -------------------------------------------------------------------------------- 1 | import styled, { css, DefaultTheme } from 'styled-components'; 2 | 3 | const Section = styled.section<{ 4 | bgColor?: keyof DefaultTheme['colors'] 5 | variant?: 'md' | 'sm', 6 | direction?: 'row' | 'column' 7 | center?: boolean, 8 | }>` 9 | 10 | display: flex; 11 | flex-direction: ${({ direction = 'row' }) => direction}; 12 | background-color: ${({ theme, bgColor = 'black' }) => theme.colors[bgColor] }; 13 | padding: 120px; 14 | ${({ variant = 'sm' }) => variant === 'sm' && css` 15 | padding: 120px 0; 16 | `}; 17 | 18 | ${({ center }) => center && css` 19 | justify-content: center; 20 | align-items: center; 21 | `} 22 | `; 23 | 24 | export default Section; -------------------------------------------------------------------------------- /Apps/web/src/index.css: -------------------------------------------------------------------------------- 1 | /* latin */ 2 | @font-face { 3 | font-family: 'Poppins'; 4 | font-style: normal; 5 | font-weight: 300; 6 | src: url(https://fonts.gstatic.com/s/poppins/v20/pxiByp8kv8JHgFVrLDz8Z1xlFQ.woff2) format('woff2'); 7 | unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; 8 | } 9 | 10 | /* latin */ 11 | @font-face { 12 | font-family: 'Poppins'; 13 | font-style: normal; 14 | font-weight: 400; 15 | src: url(https://fonts.gstatic.com/s/poppins/v20/pxiEyp8kv8JHgFVrJJfecg.woff2) format('woff2'); 16 | unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; 17 | } 18 | 19 | /* latin */ 20 | @font-face { 21 | font-family: 'Poppins'; 22 | font-style: normal; 23 | font-weight: 500; 24 | src: url(https://fonts.gstatic.com/s/poppins/v20/pxiByp8kv8JHgFVrLGT9Z1xlFQ.woff2) format('woff2'); 25 | unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; 26 | } 27 | 28 | /* latin */ 29 | @font-face { 30 | font-family: 'Poppins'; 31 | font-style: normal; 32 | font-weight: 600; 33 | src: url(https://fonts.gstatic.com/s/poppins/v20/pxiByp8kv8JHgFVrLEj6Z1xlFQ.woff2) format('woff2'); 34 | unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; 35 | } 36 | 37 | /* latin */ 38 | @font-face { 39 | font-family: 'Poppins'; 40 | font-style: normal; 41 | font-weight: 700; 42 | src: url(https://fonts.gstatic.com/s/poppins/v20/pxiByp8kv8JHgFVrLCz7Z1xlFQ.woff2) format('woff2'); 43 | unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; 44 | } 45 | 46 | :root { 47 | font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; 48 | line-height: 1.5; 49 | font-weight: 400; 50 | 51 | color-scheme: light dark; 52 | color: rgba(255, 255, 255, 0.87); 53 | background-color: #242424; 54 | 55 | font-synthesis: none; 56 | text-rendering: optimizeLegibility; 57 | -webkit-font-smoothing: antialiased; 58 | -moz-osx-font-smoothing: grayscale; 59 | -webkit-text-size-adjust: 100%; 60 | } 61 | 62 | html, body { 63 | margin: 0; 64 | } 65 | 66 | html { 67 | box-sizing: border-box; 68 | } 69 | 70 | *, *:before, *:after { 71 | box-sizing: inherit; 72 | } 73 | -------------------------------------------------------------------------------- /Apps/web/src/main.tsx: -------------------------------------------------------------------------------- 1 | import ReactDOM from 'react-dom/client'; 2 | import { ThemeProvider } from 'styled-components'; 3 | import App from './App'; 4 | import { theme } from './commonTheme/theme'; 5 | import './index.css'; 6 | 7 | ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render( 8 | 9 | 10 | 11 | ); 12 | -------------------------------------------------------------------------------- /Apps/web/src/theme.d.ts: -------------------------------------------------------------------------------- 1 | import 'styled-components'; 2 | 3 | declare module 'styled-components' { 4 | export interface DefaultTheme { 5 | colors: { 6 | primary: string, 7 | black: string, 8 | gray: string, 9 | darkGray: string, 10 | white: string 11 | }, 12 | media: { 13 | mobile: string, 14 | } 15 | sizes: { 16 | desktopMaxWidth: string 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /Apps/web/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /Apps/web/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "useDefineForClassFields": true, 5 | "lib": ["DOM", "DOM.Iterable", "ESNext"], 6 | "allowJs": false, 7 | "skipLibCheck": true, 8 | "esModuleInterop": false, 9 | "allowSyntheticDefaultImports": true, 10 | "strict": true, 11 | "forceConsistentCasingInFileNames": true, 12 | "module": "ESNext", 13 | "moduleResolution": "Node", 14 | "resolveJsonModule": true, 15 | "isolatedModules": true, 16 | "noEmit": true, 17 | "jsx": "react-jsx" 18 | }, 19 | "include": ["src"], 20 | "references": [{ "path": "./tsconfig.node.json" }] 21 | } 22 | -------------------------------------------------------------------------------- /Apps/web/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "module": "ESNext", 5 | "moduleResolution": "Node", 6 | "allowSyntheticDefaultImports": true 7 | }, 8 | "include": ["vite.config.ts"] 9 | } 10 | -------------------------------------------------------------------------------- /Apps/web/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite'; 2 | import react from '@vitejs/plugin-react-swc'; 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | }); 8 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | # Open Pato License 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | 1. **Attribution**: The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | 1. **Open Source Requirement**: Any derivative works, modifications, or distributions of the Software, in whole or in part, must be made available to the public as open-source software. The source code of such derivative works or distributions must be made publicly accessible and free of charge, and must be licensed under the same terms as this Open Pato License. 14 | 15 | 1. **Duck Protection Clause**: The use of this software, directly or indirectly, 16 | to harm ducks or any duck-related activities is strictly prohibited. Furthermore, 17 | any attempt to rename the software project to a name associated with geese, directly 18 | or indirectly, is also prohibited. 19 | 20 | 1. **AI Model Restriction Clause**: The use of the source code, art, sound or any assets in this software for training or 21 | operating artificial intelligence models, including but not limited to machine learning models, 22 | neural networks, or any other AI systems, is strictly prohibited. 23 | 24 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 25 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 26 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 27 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 28 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 29 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30 | SOFTWARE. -------------------------------------------------------------------------------- /Lib/quackscript/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "browser": true, 4 | "es2021": true 5 | }, 6 | "extends": [ 7 | "eslint:recommended", 8 | "plugin:@typescript-eslint/recommended" 9 | ], 10 | "overrides": [ 11 | ], 12 | "parser": "@typescript-eslint/parser", 13 | "parserOptions": { 14 | "ecmaVersion": "latest", 15 | "sourceType": "module" 16 | }, 17 | "plugins": [ 18 | "@typescript-eslint" 19 | ], 20 | "rules": { 21 | "indent": [ 22 | "error", 23 | 4 24 | ], 25 | "linebreak-style": [ 26 | "error", 27 | "unix" 28 | ], 29 | "quotes": [ 30 | "error", 31 | "single" 32 | ], 33 | "semi": [ 34 | "error", 35 | "always" 36 | ] 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Lib/quackscript/jest.config.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * For a detailed explanation regarding each configuration property and type check, visit: 3 | * https://jestjs.io/docs/configuration 4 | */ 5 | 6 | export default { 7 | // All imported modules in your tests should be mocked automatically 8 | // automock: false, 9 | 10 | // Stop running tests after `n` failures 11 | // bail: 0, 12 | 13 | // The directory where Jest should store its cached dependency information 14 | // cacheDirectory: "C:\\Users\\niv3k\\AppData\\Local\\Temp\\jest", 15 | 16 | // Automatically clear mock calls, instances, contexts and results before every test 17 | clearMocks: true, 18 | 19 | // Indicates whether the coverage information should be collected while executing the test 20 | collectCoverage: false, 21 | 22 | // An array of glob patterns indicating a set of files for which coverage information should be collected 23 | // collectCoverageFrom: undefined, 24 | 25 | // The directory where Jest should output its coverage files 26 | coverageDirectory: 'coverage', 27 | 28 | // An array of regexp pattern strings used to skip coverage collection 29 | // coveragePathIgnorePatterns: [ 30 | // "\\\\node_modules\\\\" 31 | // ], 32 | 33 | // Indicates which provider should be used to instrument code for coverage 34 | coverageProvider: 'v8', 35 | 36 | // A list of reporter names that Jest uses when writing coverage reports 37 | // coverageReporters: [ 38 | // "json", 39 | // "text", 40 | // "lcov", 41 | // "clover" 42 | // ], 43 | 44 | // An object that configures minimum threshold enforcement for coverage results 45 | // coverageThreshold: undefined, 46 | 47 | // A path to a custom dependency extractor 48 | // dependencyExtractor: undefined, 49 | 50 | // Make calling deprecated APIs throw helpful error messages 51 | // errorOnDeprecated: false, 52 | 53 | // The default configuration for fake timers 54 | // fakeTimers: { 55 | // "enableGlobally": false 56 | // }, 57 | 58 | // Force coverage collection from ignored files using an array of glob patterns 59 | // forceCoverageMatch: [], 60 | 61 | // A path to a module which exports an async function that is triggered once before all test suites 62 | // globalSetup: undefined, 63 | 64 | // A path to a module which exports an async function that is triggered once after all test suites 65 | // globalTeardown: undefined, 66 | 67 | // A set of global variables that need to be available in all test environments 68 | // globals: {}, 69 | 70 | // The maximum amount of workers used to run your tests. Can be specified as % or a number. E.g. maxWorkers: 10% will use 10% of your CPU amount + 1 as the maximum worker number. maxWorkers: 2 will use a maximum of 2 workers. 71 | // maxWorkers: "50%", 72 | 73 | // An array of directory names to be searched recursively up from the requiring module's location 74 | // moduleDirectories: [ 75 | // "node_modules" 76 | // ], 77 | 78 | // An array of file extensions your modules use 79 | // moduleFileExtensions: [ 80 | // "js", 81 | // "mjs", 82 | // "cjs", 83 | // "jsx", 84 | // "ts", 85 | // "tsx", 86 | // "json", 87 | // "node" 88 | // ], 89 | 90 | // A map from regular expressions to module names or to arrays of module names that allow to stub out resources with a single module 91 | // moduleNameMapper: {}, 92 | 93 | // An array of regexp pattern strings, matched against all module paths before considered 'visible' to the module loader 94 | // modulePathIgnorePatterns: [], 95 | 96 | // Activates notifications for test results 97 | // notify: false, 98 | 99 | // An enum that specifies notification mode. Requires { notify: true } 100 | // notifyMode: "failure-change", 101 | 102 | // A preset that is used as a base for Jest's configuration 103 | preset: 'ts-jest', 104 | 105 | // Run tests from one or more projects 106 | // projects: undefined, 107 | 108 | // Use this configuration option to add custom reporters to Jest 109 | // reporters: undefined, 110 | 111 | // Automatically reset mock state before every test 112 | // resetMocks: false, 113 | 114 | // Reset the module registry before running each individual test 115 | // resetModules: false, 116 | 117 | // A path to a custom resolver 118 | // resolver: undefined, 119 | 120 | // Automatically restore mock state and implementation before every test 121 | // restoreMocks: false, 122 | 123 | // The root directory that Jest should scan for tests and modules within 124 | // rootDir: undefined, 125 | 126 | // A list of paths to directories that Jest should use to search for files in 127 | // roots: [ 128 | // "" 129 | // ], 130 | 131 | // Allows you to use a custom runner instead of Jest's default test runner 132 | // runner: "jest-runner", 133 | 134 | // The paths to modules that run some code to configure or set up the testing environment before each test 135 | // setupFiles: [], 136 | 137 | // A list of paths to modules that run some code to configure or set up the testing framework before each test 138 | // setupFilesAfterEnv: [], 139 | 140 | // The number of seconds after which a test is considered as slow and reported as such in the results. 141 | // slowTestThreshold: 5, 142 | 143 | // A list of paths to snapshot serializer modules Jest should use for snapshot testing 144 | // snapshotSerializers: [], 145 | 146 | // The test environment that will be used for testing 147 | // testEnvironment: "jest-environment-node", 148 | 149 | // Options that will be passed to the testEnvironment 150 | // testEnvironmentOptions: {}, 151 | 152 | // Adds a location field to test results 153 | // testLocationInResults: false, 154 | 155 | // The glob patterns Jest uses to detect test files 156 | // testMatch: [ 157 | // "**/__tests__/**/*.[jt]s?(x)", 158 | // "**/?(*.)+(spec|test).[tj]s?(x)" 159 | // ], 160 | 161 | // An array of regexp pattern strings that are matched against all test paths, matched tests are skipped 162 | // testPathIgnorePatterns: [ 163 | // "\\\\node_modules\\\\" 164 | // ], 165 | 166 | // The regexp pattern or array of patterns that Jest uses to detect test files 167 | // testRegex: [], 168 | 169 | // This option allows the use of a custom results processor 170 | // testResultsProcessor: undefined, 171 | 172 | // This option allows use of a custom test runner 173 | // testRunner: "jest-circus/runner", 174 | 175 | // A map from regular expressions to paths to transformers 176 | // transform: undefined, 177 | 178 | // An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation 179 | // transformIgnorePatterns: [ 180 | // "\\\\node_modules\\\\", 181 | // "\\.pnp\\.[^\\\\]+$" 182 | // ], 183 | 184 | // An array of regexp pattern strings that are matched against all modules before the module loader will automatically return a mock for them 185 | // unmockedModulePathPatterns: undefined, 186 | 187 | // Indicates whether each individual test should be reported during the run 188 | // verbose: undefined, 189 | 190 | // An array of regexp patterns that are matched against all source file paths before re-running tests in watch mode 191 | // watchPathIgnorePatterns: [], 192 | 193 | // Whether to use watchman for file crawling 194 | // watchman: true, 195 | }; 196 | -------------------------------------------------------------------------------- /Lib/quackscript/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "quackscript", 3 | "version": "1.0.0", 4 | "main": "src/index.js", 5 | "license": "MIT", 6 | "dependencies": { 7 | "@types/jest": "^29.5.0", 8 | "@types/node": "^18.15.3", 9 | "eslint": "^8.36.0", 10 | "jest": "^29.5.0", 11 | "ts-jest": "^29.0.5", 12 | "ts-node": "^10.9.1", 13 | "typescript": "^5.0.2" 14 | }, 15 | "devDependencies": { 16 | "@typescript-eslint/eslint-plugin": "^5.55.0", 17 | "@typescript-eslint/parser": "^5.55.0" 18 | }, 19 | "scripts": { 20 | "test": "jest", 21 | "test-watch": "jest --watchAll" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Lib/quackscript/src/exception/ControlFlowException.ts: -------------------------------------------------------------------------------- 1 | import { Value } from '../interpreter/types'; 2 | 3 | export type ControlFlowType = 'Break' | 'Return' | 'Continue'; 4 | 5 | // Break 6 | // Continue 7 | // Return 8 | export class ControlFlowException { 9 | 10 | public type: ControlFlowType; 11 | public data: Value; 12 | 13 | constructor (type: ControlFlowType, data?: Value | null | void) { 14 | this.type = type; 15 | this.data = data ?? { 16 | type: 'NothingLiteral', 17 | } as Value; 18 | } 19 | } -------------------------------------------------------------------------------- /Lib/quackscript/src/exception/ParseException.ts: -------------------------------------------------------------------------------- 1 | import { Position } from '../types/Position'; 2 | 3 | export class ParseException { 4 | 5 | public placement: Position; 6 | 7 | public message: string; 8 | 9 | constructor(placement: Position, message:string){ 10 | this.placement = placement; 11 | this.message = message; 12 | } 13 | 14 | toString() { 15 | return `Parse Error: In line ${this.placement.line} at char ${this.placement.lineChar} \n ${this.message}`; 16 | } 17 | } -------------------------------------------------------------------------------- /Lib/quackscript/src/exception/RuntimeException.ts: -------------------------------------------------------------------------------- 1 | import { Position } from '../types/Position'; 2 | 3 | export class RuntimeException { 4 | 5 | public code: string | null; 6 | 7 | public position: Position; 8 | 9 | public message: string; 10 | 11 | constructor(position: Position, message:string, code?: string | null){ 12 | this.position = position; 13 | this.message = message; 14 | this.code = code ?? null; 15 | } 16 | 17 | toString() { 18 | let msg = `Runtime Error: In line ${this.position.line} at char ${this.position.lineChar}\n ${this.message}`; 19 | 20 | if (this.code !== null) { 21 | console.log(this.position); 22 | const line = this.code.split('\n')[this.position.line - 1]; 23 | if (line) { 24 | msg += `\n${line}\n`; 25 | msg += '^'.padStart(this.position.lineChar + 1); 26 | } 27 | } 28 | return msg; 29 | } 30 | } -------------------------------------------------------------------------------- /Lib/quackscript/src/exception/SyntaxException.ts: -------------------------------------------------------------------------------- 1 | import { Position } from '../types/Position'; 2 | 3 | export class SyntaxException { 4 | 5 | public placement: Position; 6 | 7 | public message: string; 8 | 9 | constructor(placement: Position, message:string){ 10 | this.placement = placement; 11 | this.message = message; 12 | } 13 | 14 | toString() { 15 | return `Syntax Error: In line ${this.placement.line} at char ${this.placement.lineChar} \n ${this.message}`; 16 | } 17 | } -------------------------------------------------------------------------------- /Lib/quackscript/src/index.ts: -------------------------------------------------------------------------------- 1 | import P from './parser'; 2 | import I from './interpreter'; 3 | import L from './lexer'; 4 | 5 | export const Parser = P; 6 | export const Interpreter = I; 7 | export const Lexer = L; 8 | 9 | const QuackScript = { 10 | }; 11 | 12 | export default QuackScript; -------------------------------------------------------------------------------- /Lib/quackscript/src/interpreter/memory.ts: -------------------------------------------------------------------------------- 1 | import { DataTypeUtils } from '../utils/dataTypes/dataTypeUtils'; 2 | import standardLibrary from '../stdLibrary/standardLibrary'; 3 | import { MemoryValue, OptionalMemoryValue, OptionalValueNode, Value } from './types'; 4 | import { RuntimeException } from '../exception/RuntimeException'; 5 | 6 | export type Scope = { 7 | subScope: Scope | null, 8 | data: Record 9 | }; 10 | 11 | export class Memory { 12 | 13 | private _memory: Scope; 14 | 15 | constructor () { 16 | this._memory = { subScope: null, data: { 17 | ...standardLibrary 18 | } }; 19 | } 20 | 21 | public clearMemory() { 22 | this._memory = { subScope: null, data: { 23 | ...standardLibrary 24 | } }; 25 | } 26 | 27 | public clearScope() { 28 | let scope: Scope | null = this._memory; 29 | 30 | if (scope.subScope === null) { 31 | this.clearMemory(); 32 | return; 33 | } 34 | 35 | do { 36 | if (scope.subScope?.subScope === null) { 37 | scope.subScope = null; 38 | } 39 | scope = scope.subScope; 40 | } while (scope !== null); 41 | } 42 | 43 | public delete(identifier: string) { 44 | const scope = this.getActiveScope(); 45 | if (scope) { 46 | delete scope.data[identifier]; 47 | } 48 | } 49 | 50 | /** 51 | * gets a value from memory 52 | * @throws error when variable not in memory 53 | */ 54 | public get(identifier: string): MemoryValue { 55 | const allScopes = this.getAllScopesInOrder().reverse(); 56 | for (const scope of allScopes) { 57 | const value = scope.data[identifier]; 58 | if (value) return value; 59 | } 60 | console.log(this._memory); 61 | throw new Error(`Variable '${identifier}' not in memory`); 62 | } 63 | 64 | public createScope() { 65 | const scope = this.getActiveScope(); 66 | scope.subScope = { data: {}, subScope: null}; 67 | } 68 | 69 | public set(identifier: string, value: MemoryValue) { 70 | const scope = this.getActiveScope(); 71 | const memorySlot = scope.data[identifier]; 72 | if (memorySlot) throw new Error(`Variable '${identifier}' already exists`); 73 | 74 | const valueType = DataTypeUtils.valueToDataType(value.value.type); 75 | 76 | let dataNodeType = value.type; 77 | if (dataNodeType === 'optional') { 78 | dataNodeType = (value as OptionalMemoryValue).internalType; 79 | if (dataNodeType === 'internalFunc'){ 80 | throw new RuntimeException(value.value.position, 'Tried to assign internal function'); 81 | } 82 | 83 | if (valueType !== 'nothing' && valueType !== dataNodeType){ 84 | throw new RuntimeException(value.value.position, `Tried to assign ${valueType} to optional<${dataNodeType}>`); 85 | } 86 | 87 | const valueToSave: OptionalValueNode = { 88 | internalType: dataNodeType, 89 | position: value.value.position, 90 | type: 'OptionalValue', 91 | value: value.value 92 | }; 93 | 94 | scope.data[identifier] = { 95 | ...value, 96 | value: valueToSave 97 | }; 98 | console.log(value.value); 99 | return; 100 | } 101 | 102 | if (dataNodeType !== valueType) { 103 | throw new Error(`Tried to assign '${valueType}' to a '${dataNodeType}'`); 104 | } 105 | 106 | scope.data[identifier] = value; 107 | } 108 | 109 | public update(identifier: string, value: Value) { 110 | const memoryItem = this.get(identifier); 111 | 112 | if (!memoryItem) throw new Error(`variable '${identifier}' does not exists`); 113 | if (memoryItem.declarationType === 'constant') throw new Error(`Tried to update constant '${identifier}'`); 114 | if (memoryItem.declarationType === 'argument') throw new Error(`Tried to update argument '${identifier}'`); 115 | const type = DataTypeUtils.valueToDataType(value.type); 116 | 117 | if (memoryItem.type === 'optional' && 118 | (memoryItem.internalType === type || type === 'nothing') 119 | ){ 120 | (memoryItem.value as OptionalValueNode).value = value; 121 | return; 122 | } 123 | 124 | if (memoryItem.type !== type) throw new Error(`Tried to assign '${type}' to a '${memoryItem.type}'`); 125 | memoryItem.value = value; 126 | } 127 | 128 | private getAllScopesInOrder() { 129 | const allScopes:Array = []; 130 | let currentScope:Scope | null = this._memory; 131 | while (currentScope !== null) { 132 | allScopes.push(currentScope); 133 | currentScope = currentScope.subScope; 134 | } 135 | return allScopes; 136 | } 137 | 138 | private getActiveScope(){ 139 | let scope: Scope | null = this._memory; 140 | do { 141 | if (scope.subScope === null){ 142 | return scope; 143 | } 144 | scope = scope.subScope; 145 | } while (scope !== null); 146 | return scope; 147 | } 148 | 149 | public printMemory() { 150 | console.log(this._memory); 151 | } 152 | } 153 | 154 | -------------------------------------------------------------------------------- /Lib/quackscript/src/interpreter/state.ts: -------------------------------------------------------------------------------- 1 | export type StateType = 'topLevel' | 'function' | 'while' | 'for'; 2 | 3 | // TODO - fix issue with nested function returns 4 | export class State { 5 | private _stateStack: Array; 6 | 7 | constructor(){ 8 | this._stateStack = ['topLevel']; 9 | } 10 | 11 | public push(state: Exclude){ 12 | this._stateStack.push(state); 13 | } 14 | 15 | public pop(){ 16 | return this._stateStack.pop(); 17 | } 18 | 19 | public getCurrentState(){ 20 | const currentState = this._stateStack[this._stateStack.length - 1]; 21 | if (!currentState) throw new Error('Internal state error'); 22 | return currentState; 23 | } 24 | 25 | public popToTopLevel(){ 26 | this._stateStack = ['topLevel']; 27 | } 28 | } -------------------------------------------------------------------------------- /Lib/quackscript/src/interpreter/staticPrimitiveAttributes.ts: -------------------------------------------------------------------------------- 1 | import { RuntimeException } from '../exception/RuntimeException'; 2 | import { DataTypes, IdentifierNode } from '../parser/types'; 3 | import { DataTypeUtils } from '../utils/dataTypes/dataTypeUtils'; 4 | import { MemoryUtils } from '../utils/memory/memoryUtils'; 5 | import { MemoryValue, OptionalValueNode, Value } from './types'; 6 | 7 | const staticAttributeMap: Record> = { 8 | 'number': { 9 | }, 10 | 'boolean': { 11 | }, 12 | 'func': { 13 | }, 14 | 'list': { 15 | }, 16 | 'nothing': { 17 | }, 18 | 'optional': { 19 | 'unwrap': MemoryUtils.convertToInternalFunc('unwrap', []) 20 | }, 21 | 'text': { 22 | }, 23 | 'vector2': { 24 | }, 25 | 'vector3': { 26 | }, 27 | }; 28 | 29 | const commonStaticAttributeMap: Record = { 30 | 'toText': MemoryUtils.convertToInternalFunc('toText', []), 31 | }; 32 | 33 | const executeStaticOptionalFunction = (identifier: IdentifierNode, value: OptionalValueNode):Value => { 34 | const dataType = DataTypeUtils.valueToDataType(value.type); 35 | switch (identifier.value){ 36 | case 'unwrap': 37 | if (value.value.type === 'NothingLiteral') { 38 | throw new Error('Unwrapped a optional with nothing inside'); 39 | } 40 | return value.value; 41 | } 42 | throw new RuntimeException(value.position, `Attribute '${identifier.value}' is not part of ${dataType}`); 43 | }; 44 | 45 | const executeStaticFunction = (identifier: IdentifierNode, value: Value):Value => { 46 | const dataType = DataTypeUtils.valueToDataType(value.type); 47 | const fnSignature = getStaticPrimitiveValue(dataType, identifier); 48 | if (!fnSignature) throw new RuntimeException(value.position, 'Invalid data type'); 49 | 50 | switch (identifier.value) { 51 | case 'toText': 52 | return DataTypeUtils.convertValueToText(value); 53 | } 54 | 55 | if (value.type === 'OptionalValue') { 56 | return executeStaticOptionalFunction(identifier, value); 57 | } 58 | throw new RuntimeException(value.position, `Attribute '${identifier.value}' is not part of ${dataType}`); 59 | }; 60 | 61 | const getStaticPrimitiveValue = (type: DataTypes, identifier: IdentifierNode) => ( 62 | (commonStaticAttributeMap[identifier.value]) ?? 63 | (staticAttributeMap[type][identifier.value]) 64 | ); 65 | 66 | export const StaticPrimitiveAttributes = { 67 | getStaticPrimitiveValue, 68 | executeStaticFunction 69 | }; 70 | -------------------------------------------------------------------------------- /Lib/quackscript/src/interpreter/types.ts: -------------------------------------------------------------------------------- 1 | import { Node, DataTypes, FuncDeclarationNode, InternalFuncDeclarationNode, LiteralNode } from '../parser/types'; 2 | 3 | export type Value = LiteralNode | FuncDeclarationNode | InternalFuncDeclarationNode | OptionalValueNode; 4 | 5 | export interface MemoryValue { 6 | declarationType: 'constant' | 'variable' | 'argument' | 'internal' 7 | type: DataTypes | 'internalFunc', 8 | identifier: string, 9 | value: Value, 10 | internalType: DataTypes | 'internalFunc' | null, 11 | } 12 | 13 | export interface OptionalMemoryValue extends MemoryValue { 14 | type: 'optional', 15 | internalType: DataTypes | 'internalFunc', 16 | } 17 | 18 | export interface OptionalValueNode extends Node<'OptionalValue'> { 19 | value: Value, 20 | internalType: DataTypes 21 | } -------------------------------------------------------------------------------- /Lib/quackscript/src/lexer/__tests__/keywords.test.ts: -------------------------------------------------------------------------------- 1 | import Lexer from '..'; 2 | import { Lexemes } from '../../types/Lexemes'; 3 | 4 | describe('Keywords - ', () => { 5 | 6 | const keywordValuesToTest: Array<{ 7 | value: string, 8 | expectedType: Lexemes, 9 | isValid: boolean 10 | }> = [ 11 | { value: 'return', expectedType: 'RETURN', isValid: true }, 12 | { value: 'returnTest', expectedType: 'IDENTIFIER', isValid: true }, 13 | { value: 'if', expectedType: 'IF', isValid: true }, 14 | { value: 'ifA', expectedType: 'IDENTIFIER', isValid: true }, 15 | { value: 'then', expectedType: 'THEN', isValid: true }, 16 | { value: 'thenA', expectedType: 'IDENTIFIER', isValid: true }, 17 | { value: 'else', expectedType: 'ELSE', isValid: true }, 18 | { value: 'elseA', expectedType: 'IDENTIFIER', isValid: true }, 19 | { value: 'optional', expectedType: 'OPTIONAL_TYPE', isValid: true }, 20 | { value: 'optionalA', expectedType: 'IDENTIFIER', isValid: true }, 21 | { value: 'number', expectedType: 'NUMBER_TYPE', isValid: true }, 22 | { value: 'numberA', expectedType: 'IDENTIFIER', isValid: true }, 23 | { value: 'text', expectedType: 'TEXT_TYPE', isValid: true }, 24 | { value: 'textA', expectedType: 'IDENTIFIER', isValid: true }, 25 | { value: 'boolean', expectedType: 'BOOLEAN_TYPE', isValid: true }, 26 | { value: 'booleanA', expectedType: 'IDENTIFIER', isValid: true }, 27 | { value: 'nothing', expectedType: 'NOTHING', isValid: true }, 28 | { value: 'nothingA', expectedType: 'IDENTIFIER', isValid: true }, 29 | { value: 'vector2', expectedType: 'VECTOR2', isValid: true }, 30 | { value: 'vector2A', expectedType: 'IDENTIFIER', isValid: true }, 31 | { value: 'vector3', expectedType: 'VECTOR3', isValid: true }, 32 | { value: 'vector3a', expectedType: 'IDENTIFIER', isValid: true }, 33 | { value: 'func', expectedType: 'FUNC_TYPE', isValid: true }, 34 | { value: 'funcA', expectedType: 'IDENTIFIER', isValid: true }, 35 | { value: 'import', expectedType: 'IMPORT', isValid: true }, 36 | { value: 'importA', expectedType: 'IDENTIFIER', isValid: true }, 37 | ]; 38 | 39 | test.each(keywordValuesToTest)('Keyword: \'%s\'', ({ value, isValid, expectedType }) => { 40 | const lexer = new Lexer(); 41 | const outcome = lexer.convertToTokens(value); 42 | const isEqual = ( 43 | outcome[0]?.type === expectedType && 44 | outcome[0]?.value === value 45 | ); 46 | expect(isEqual).toBe(isValid); 47 | }); 48 | 49 | }); -------------------------------------------------------------------------------- /Lib/quackscript/src/lexer/__tests__/lexemes.test.ts: -------------------------------------------------------------------------------- 1 | import Lexer from '..'; 2 | import { Lexemes } from '../../types/Lexemes'; 3 | import { Token } from '../../types/Token'; 4 | 5 | describe('Lexemes - ', () => { 6 | const valuesToTest: Array< 7 | { 8 | value: string, 9 | expectedType: Lexemes, 10 | expectedParsedValue?: string 11 | } 12 | > = [ 13 | { value: '23', expectedType: 'NUMBER_VALUE' }, 14 | { value: '23.123', expectedType: 'NUMBER_VALUE' }, 15 | { value: 'test', expectedType: 'IDENTIFIER' }, 16 | { value: 'asd123', expectedType: 'IDENTIFIER' }, 17 | { value: 'number', expectedType: 'NUMBER_TYPE' }, 18 | { value: '+', expectedType: 'ADDITION' }, 19 | { value: '-', expectedType: 'SUBTRACTION' }, 20 | { value: '>', expectedType: 'GREATER_THAN' }, 21 | { value: '+', expectedType: 'ADDITION' }, 22 | { value: '-', expectedType: 'SUBTRACTION' }, 23 | { value: '*', expectedType: 'MULTIPLICATION' }, 24 | { value: '%', expectedType: 'MODULUS' }, 25 | { value: '/', expectedType: 'DIVISION' }, 26 | { value: 'quack', expectedType: 'ASSIGNMENT_LET' }, 27 | { value: 'QUACK', expectedType: 'ASSIGNMENT_CONST' }, 28 | { value: '<-', expectedType: 'ASSIGNMENT_OPERATOR' }, 29 | { value: '(', expectedType: 'BRACKET_OPEN' }, 30 | { value: ')', expectedType: 'BRACKET_CLOSE' }, 31 | { value: '[', expectedType: 'SQUARE_BRACKET_OPEN' }, 32 | { value: ']', expectedType: 'SQUARE_BRACKET_CLOSE' }, 33 | { value: '{', expectedType: 'CURLY_BRACKET_OPEN' }, 34 | { value: '}', expectedType: 'CURLY_BRACKET_CLOSE' }, 35 | { value: '\'test\'', expectedType: 'TEXT_VALUE', expectedParsedValue: 'test' }, 36 | { value: '"test"', expectedType: 'TEXT_VALUE', expectedParsedValue: 'test' }, 37 | { value: ',', expectedType: 'COMMA' }, 38 | { value: '&&', expectedType: 'AND' }, 39 | { value: '||', expectedType: 'OR' }, 40 | { value: '<=', expectedType: 'LESS_THAN_OR_EQUALS' }, 41 | { value: '<', expectedType: 'LESS_THAN' }, 42 | { value: '>=', expectedType: 'GREATER_THAN_OR_EQUALS' }, 43 | { value: '>', expectedType: 'GREATER_THAN' }, 44 | { value: '!=', expectedType: 'NOT_EQUALS' }, 45 | { value: '==', expectedType: 'EQUALS' }, 46 | { value: 'if', expectedType: 'IF' }, 47 | { value: 'then', expectedType: 'THEN' }, 48 | { value: 'else', expectedType: 'ELSE' }, 49 | { value: 'optional', expectedType: 'OPTIONAL_TYPE' }, 50 | { value: 'number', expectedType: 'NUMBER_TYPE' }, 51 | { value: 'text', expectedType: 'TEXT_TYPE' }, 52 | { value: 'true', expectedType: 'BOOLEAN_VALUE' }, 53 | { value: 'false', expectedType: 'BOOLEAN_VALUE' }, 54 | { value: 'boolean', expectedType: 'BOOLEAN_TYPE' }, 55 | { value: 'nothing', expectedType: 'NOTHING' }, 56 | { value: 'vector2', expectedType: 'VECTOR2' }, 57 | { value: 'vector3', expectedType: 'VECTOR3' }, 58 | { value: 'func', expectedType: 'FUNC_TYPE' }, 59 | { value: 'import', expectedType: 'IMPORT' }, 60 | { value: '.', expectedType: 'DOT' }, 61 | { value: '?', expectedType: 'QUESTION_MARK' }, 62 | { value: ':', expectedType: 'COLON' }, 63 | { value: '// This is a comment', expectedType: 'COMMENT_SHORT' }, 64 | { value: '// This is a comment \n', expectedType: 'COMMENT_SHORT' }, 65 | { value: '/* This is a comment */', expectedType: 'COMMENT_LONG' }, 66 | { value: '/* This is a comment \n\n\n */', expectedType: 'COMMENT_LONG' }, 67 | { value: 'return', expectedType: 'RETURN' }, 68 | { value: '\n', expectedType: 'NEW_LINE' }, 69 | { value: '🦆', expectedType: 'TERMINATOR' } 70 | ]; 71 | test.each(valuesToTest)('can parse \'%s\'', ({ expectedType, value, expectedParsedValue}) => { 72 | const lexer = new Lexer(); 73 | const outcome = lexer.convertToTokens(value); 74 | expect(outcome).toEqual([{ 75 | position: { 76 | lineChar: 1, 77 | line: 1, 78 | globalChar: 1, 79 | }, 80 | type: expectedType, 81 | value: expectedParsedValue ?? value 82 | }] as Array); 83 | }); 84 | }); -------------------------------------------------------------------------------- /Lib/quackscript/src/lexer/__tests__/literal.test.ts: -------------------------------------------------------------------------------- 1 | import Lexer from '..'; 2 | 3 | describe('Lexer Literals - ', () => { 4 | 5 | const identifierValuesToTest: Array<{ 6 | value: string, 7 | isValid: boolean 8 | }> = [ 9 | { value: 'a123123', isValid: true }, 10 | { value: 'a___a', isValid: true }, 11 | { value: '_test', isValid: true }, 12 | { value: '123test', isValid: false }, 13 | ]; 14 | test.each(identifierValuesToTest)('String literal: \'%s\'', ({ value, isValid }) => { 15 | const lexer = new Lexer(); 16 | const outcome = lexer.convertToTokens(value); 17 | const isEqual = ( 18 | outcome[0]?.type === 'IDENTIFIER' && 19 | outcome[0]?.value === value 20 | ); 21 | expect(isEqual).toBe(isValid); 22 | }); 23 | 24 | const numberValuesToTest: Array<{ 25 | value: string, 26 | isValid: boolean 27 | }> = [ 28 | { value: '2123123', isValid: true }, 29 | { value: '123.123123', isValid: true }, 30 | { value: '.1231', isValid: false }, 31 | { value: '_123', isValid: false }, 32 | { value: '123123_', isValid: false }, 33 | { value: '123test', isValid: false }, 34 | ]; 35 | test.each(numberValuesToTest)('Number Literal: \'%s\'', ({ value, isValid }) => { 36 | const lexer = new Lexer(); 37 | const outcome = lexer.convertToTokens(value); 38 | const isEqual = ( 39 | outcome[0]?.type === 'NUMBER_VALUE' && 40 | outcome[0]?.value === value 41 | ); 42 | expect(isEqual).toBe(isValid); 43 | }); 44 | }); -------------------------------------------------------------------------------- /Lib/quackscript/src/lexer/__tests__/math.test.ts: -------------------------------------------------------------------------------- 1 | import Lexer from '..'; 2 | import { Token } from '../../types/Token'; 3 | 4 | const valuesToTest: Array<{ 5 | value: string, 6 | expected: Array 7 | }> = [ 8 | { 9 | value: '10*(5+2)', 10 | expected: [ 11 | { 12 | position: { 13 | globalChar: 1, 14 | line: 1, 15 | lineChar: 1 16 | }, 17 | type: 'NUMBER_VALUE', 18 | value: '10' 19 | }, 20 | { 21 | position: { 22 | globalChar: 3, 23 | line: 1, 24 | lineChar: 3 25 | }, 26 | type: 'MULTIPLICATION', 27 | value: '*' 28 | }, 29 | { 30 | position: { 31 | globalChar: 4, 32 | line: 1, 33 | lineChar: 4 34 | }, 35 | type: 'BRACKET_OPEN', 36 | value: '(' 37 | }, 38 | { 39 | position: { 40 | globalChar: 5, 41 | line: 1, 42 | lineChar: 5 43 | }, 44 | type: 'NUMBER_VALUE', 45 | value: '5' 46 | }, 47 | { 48 | position: { 49 | globalChar: 6, 50 | line: 1, 51 | lineChar: 6 52 | }, 53 | type: 'ADDITION', 54 | value: '+' 55 | }, 56 | { 57 | position: { 58 | globalChar: 7, 59 | line: 1, 60 | lineChar: 7 61 | }, 62 | type: 'NUMBER_VALUE', 63 | value: '2' 64 | }, 65 | { 66 | position: { 67 | globalChar: 8, 68 | line: 1, 69 | lineChar: 8 70 | }, 71 | type: 'BRACKET_CLOSE', 72 | value: ')' 73 | }, 74 | ] 75 | }, 76 | { 77 | value: '125+25.0/593*20<123', 78 | expected: [ 79 | { 80 | position: { 81 | globalChar: 1, 82 | line: 1, 83 | lineChar: 1 84 | }, 85 | type: 'NUMBER_VALUE', 86 | value: '125' 87 | }, 88 | { 89 | position: { 90 | globalChar: 4, 91 | lineChar: 4, 92 | line: 1 93 | }, 94 | type: 'ADDITION', 95 | value: '+' 96 | }, 97 | { 98 | position: { 99 | globalChar: 5, 100 | lineChar: 5, 101 | line: 1 102 | }, 103 | type: 'NUMBER_VALUE', 104 | value: '25.0' 105 | }, 106 | { 107 | position: { 108 | globalChar: 9, 109 | lineChar: 9, 110 | line: 1 111 | }, 112 | type: 'DIVISION', 113 | value: '/' 114 | }, 115 | { 116 | position: { 117 | globalChar: 10, 118 | lineChar: 10, 119 | line: 1 120 | }, 121 | type: 'NUMBER_VALUE', 122 | value: '593' 123 | }, 124 | { 125 | position: { 126 | globalChar: 13, 127 | lineChar: 13, 128 | line: 1 129 | }, 130 | type: 'MULTIPLICATION', 131 | value: '*' 132 | }, 133 | { 134 | position: { 135 | globalChar: 14, 136 | lineChar: 14, 137 | line: 1 138 | }, 139 | type: 'NUMBER_VALUE', 140 | value: '20' 141 | }, 142 | { 143 | position: { 144 | globalChar: 16, 145 | lineChar: 16, 146 | line: 1 147 | }, 148 | type: 'LESS_THAN', 149 | value: '<' 150 | }, 151 | { 152 | position: { 153 | globalChar: 17, 154 | lineChar: 17, 155 | line: 1 156 | }, 157 | type: 'NUMBER_VALUE', 158 | value: '123' 159 | }, 160 | ] 161 | }, 162 | { 163 | value: '1 + 2', 164 | expected: [{ 165 | position: { 166 | lineChar: 1, 167 | line: 1, 168 | globalChar: 1, 169 | }, 170 | type: 'NUMBER_VALUE', 171 | value: '1' 172 | }, 173 | { 174 | position: { 175 | lineChar: 2, 176 | line: 1, 177 | globalChar: 2, 178 | }, 179 | type: 'WHITESPACE', 180 | value: ' ' 181 | }, 182 | { 183 | position: { 184 | lineChar: 3, 185 | line: 1, 186 | globalChar: 3, 187 | }, 188 | type: 'ADDITION', 189 | value: '+' 190 | }, 191 | { 192 | position: { 193 | lineChar: 4, 194 | line: 1, 195 | globalChar: 4, 196 | }, 197 | type: 'WHITESPACE', 198 | value: ' ' 199 | }, 200 | { 201 | position: { 202 | lineChar: 5, 203 | line: 1, 204 | globalChar: 5, 205 | }, 206 | type: 'NUMBER_VALUE', 207 | value: '2' 208 | } 209 | ] 210 | } 211 | ]; 212 | 213 | 214 | describe('Lexer Math - ', () => { 215 | 216 | test.each(valuesToTest)('Math expression: \'%s\'', ({ value, expected }) => { 217 | const lexer = new Lexer(); 218 | const outcome = lexer.convertToTokens(value); 219 | expect(outcome).toEqual(expected); 220 | }); 221 | }); -------------------------------------------------------------------------------- /Lib/quackscript/src/lexer/index.ts: -------------------------------------------------------------------------------- 1 | import { SyntaxException } from '../exception/SyntaxException'; 2 | import { Lexemes } from '../types/Lexemes'; 3 | import { Position } from '../types/Position'; 4 | import { Token } from '../types/Token'; 5 | import { tokenMap } from './tokenMap'; 6 | 7 | class ErrorHandler { 8 | private _errorStack: Array = []; 9 | private _currentError?: { 10 | startPosition: Position, 11 | endPosition: Position, 12 | value: string 13 | } | null; 14 | 15 | public pushError(position: Position, value: string) { 16 | if (this._currentError) { 17 | this._currentError.endPosition = { ...position }; 18 | this._currentError.value = this._currentError.value.concat(value); 19 | return; 20 | } 21 | this._currentError = { 22 | endPosition: { ...position }, 23 | startPosition: { ...position }, 24 | value 25 | }; 26 | } 27 | 28 | public clearCurrentError() { 29 | if (!this._currentError) return; 30 | 31 | this._errorStack.push( 32 | new SyntaxException(this._currentError.startPosition, 33 | `Invalid character '${this._currentError.value}'` 34 | ) 35 | ); 36 | 37 | this._currentError = null; 38 | } 39 | 40 | public combineErrors(): string | undefined { 41 | this.clearCurrentError(); 42 | if (!this._errorStack.length) return; 43 | console.log(this._errorStack); 44 | return this._errorStack.join('\n\n'); 45 | } 46 | } 47 | 48 | export default class Lexer { 49 | private _position: Position; 50 | private _tokens: Array; 51 | private _errorHandler: ErrorHandler; 52 | 53 | constructor() { 54 | this._position = { 55 | lineChar: 1, 56 | line: 1, 57 | globalChar: 1 // cursor 58 | }; 59 | this._tokens = []; 60 | this._errorHandler = new ErrorHandler(); 61 | } 62 | 63 | public convertToTokens(code: string): Array { 64 | this._errorHandler = new ErrorHandler(); 65 | this._tokens = []; 66 | this._position = { 67 | lineChar: 1, 68 | line: 1, 69 | globalChar: 1 70 | }; 71 | 72 | const tokenKeys = Object.keys(tokenMap) as Array; 73 | tokenLoop:while (code.length) { 74 | for (const tokenKey of tokenKeys) { 75 | const result = this.parseToken(code, tokenKey); 76 | if (!result) continue; 77 | this._errorHandler.clearCurrentError(); 78 | this._tokens.push({ 79 | type: result.token, 80 | value: result.value, 81 | position: { ...this._position }, 82 | }); 83 | this._position.lineChar += result.value.length; 84 | this._position.globalChar += result.value.length; 85 | 86 | if (result.token === 'NEW_LINE') { 87 | this._position.lineChar = 1; 88 | this._position.line += 1; 89 | } 90 | 91 | code = result.splicedCode; 92 | continue tokenLoop; 93 | } 94 | 95 | const currentToken = code[0]; 96 | if (currentToken?.length) { 97 | this._errorHandler.pushError(this._position, currentToken); 98 | this._position.lineChar += 1; 99 | this._position.globalChar += 1; 100 | } 101 | code = code.substring(1); 102 | } 103 | 104 | const errors = this._errorHandler.combineErrors(); 105 | if (errors) { 106 | throw new Error(errors); 107 | } 108 | 109 | return this._tokens; 110 | } 111 | 112 | private parseToken = (data: string, token: Lexemes) => { 113 | const regexToExecute = tokenMap[token]; 114 | if (!regexToExecute) return; 115 | 116 | const result = this.extractTokenWithRegex(data, regexToExecute); 117 | if (!result) return; 118 | 119 | if (token === 'TEXT_VALUE' && result.matchedValue) { 120 | result.matchedValue = result.matchedValue.replace(/'|"/g, ''); 121 | } 122 | 123 | return { 124 | token, 125 | value: result.matchedValue, 126 | splicedCode: result.splicedCode 127 | }; 128 | }; 129 | 130 | private extractTokenWithRegex = (code: string, regexList: Array) => { 131 | for (const regex of regexList) { 132 | const result = regex.exec(code); 133 | if (!result || !result[0]) continue; 134 | const matchedValue = result?.['groups']?.['target'] ?? result[0]; 135 | const splicedCode = code.substring(matchedValue.length); 136 | 137 | return { matchedValue, splicedCode }; 138 | } 139 | }; 140 | } -------------------------------------------------------------------------------- /Lib/quackscript/src/lexer/tokenMap.ts: -------------------------------------------------------------------------------- 1 | import { Lexemes } from '../types/Lexemes'; 2 | 3 | export const tokenMap: Record> = { 4 | 'COMMENT_SHORT': [/^\/\/.*?(\n|$)/], 5 | 6 | 'COMMENT_LONG': [/^\/\*(\s|\S)*\*\//], 7 | 8 | 'RETURN': [/^return(?=[^a-z-A-Z0-9]|$)/], 9 | 10 | 'NUMBER_VALUE': [/^[0-9]+(\.[0-9])?[0-9]*/], 11 | 12 | 'WHITESPACE': [/^[^\S\n]+/], 13 | 14 | 'NEW_LINE': [/^\n/], 15 | 16 | 'TERMINATOR': [/^🦆/], 17 | 18 | 'SUBTRACTION': [/^-/], 19 | 20 | 'MULTIPLICATION': [/^\*/], 21 | 22 | 'ADDITION': [/^\+/], 23 | 24 | 'MODULUS': [/^%/], 25 | 26 | 'DIVISION': [/^\//], 27 | 28 | 'ASSIGNMENT_LET': [/^quack(?=[^a-zA-Z0-9]|$)/], 29 | 30 | 'ASSIGNMENT_CONST': [/^QUACK(?=[^a-zA-Z0-9]|$)/], 31 | 32 | 'ASSIGNMENT_OPERATOR': [/^<-/], 33 | 34 | 'BRACKET_OPEN': [/^\(/], 35 | 36 | 'BRACKET_CLOSE': [/^\)/], 37 | 38 | 'SQUARE_BRACKET_OPEN': [/^\[/], 39 | 40 | 'SQUARE_BRACKET_CLOSE': [/^\]/], 41 | 42 | 'CURLY_BRACKET_OPEN': [/^{/], 43 | 44 | 'CURLY_BRACKET_CLOSE': [/^}/], 45 | 46 | 'TEXT_VALUE': [ 47 | /^'.*?'/, 48 | /^".*?"/, 49 | ], 50 | 51 | 'COMMA': [/^,/], 52 | 53 | 'AND': [/^&&/], 54 | 55 | 'OR': [/^\|\|/], 56 | 57 | 'LESS_THAN_OR_EQUALS': [/^<=/], 58 | 59 | 'LESS_THAN': [/^=/], 62 | 63 | 'GREATER_THAN': [/^>/], 64 | 65 | 'NOT_EQUALS': [/^!=/], 66 | 67 | 'EQUALS': [/^==/], 68 | 69 | 'IF': [/^if(?=[^a-zA-Z0-9]|$)/], 70 | 71 | 'THEN': [/^then(?=[^a-zA-Z0-9]|$)/], 72 | 73 | 'ELSE': [/^else(?=[^a-z-A-Z0-9]|$)/], 74 | 75 | 'OPTIONAL_TYPE': [/^optional(?=[^a-zA-Z0-9]|$)/], 76 | 77 | 'NUMBER_TYPE': [/^number(?=[^a-z-A-Z0-9]|$)/], 78 | 79 | 'TEXT_TYPE': [/^text(?=[^a-zA-Z0-9]|$)/], 80 | 81 | 'BOOLEAN_VALUE': [/^true|^false(?=[^a-zA-Z0-9]|$)/], 82 | 83 | 'BOOLEAN_TYPE': [/^boolean(?=[^a-zA-Z0-9]|$)/], 84 | 85 | 'NOTHING': [/^nothing(?=[^a-zA-Z0-9]|$)/], 86 | 87 | 'VECTOR2': [/^vector2(?=[^a-zA-Z0-9]|$)/], 88 | 89 | 'VECTOR3': [/^vector3(?=[^a-zA-Z0-9]|$)/], 90 | 91 | 'FUNC_TYPE': [/^func(?=[^a-zA-Z0-9]|$)/], 92 | 93 | 'IMPORT': [/^import(?=[^a-zA-Z0-9]|$)/], 94 | 95 | 'DOT': [/^\./], 96 | 97 | 'QUESTION_MARK': [/^\?/], 98 | 99 | 'COLON': [/^:/], 100 | 101 | 'IDENTIFIER': [/^[a-zA-Z_]+[a-zA-Z0-9_]*/], 102 | }; -------------------------------------------------------------------------------- /Lib/quackscript/src/parser/Cursor/index.ts: -------------------------------------------------------------------------------- 1 | import { Lexemes } from '../../types/Lexemes'; 2 | import { Position } from '../../types/Position'; 3 | import { Token } from '../../types/Token'; 4 | 5 | export class Cursor { 6 | private _position: number; 7 | private _tokens:Array; 8 | 9 | constructor (tokens: Array) { 10 | this._tokens = tokens; 11 | this._position = 0; 12 | } 13 | 14 | public hasReachedEnd = () => ( 15 | this._position > this._tokens.length - 1 16 | ); 17 | 18 | public getPosition = () => { 19 | return this._position; 20 | }; 21 | 22 | public readCurrentToken = () => { 23 | return this._tokens[this._position]; 24 | }; 25 | 26 | public readCurrentTokenAndAdvanceByOne = () => { 27 | const currentToken = this._tokens[this._position]; 28 | this.advanceCursor(1); 29 | return currentToken; 30 | }; 31 | 32 | public advanceCursor = (amount: number) => { 33 | this._position += amount; 34 | }; 35 | 36 | public lookAhead = (amount: number) => { 37 | return this._tokens[this._position + amount]; 38 | }; 39 | 40 | public getCurrentPositionOrLastVisited = ():Position => { 41 | // Forcing non null because we know if we have advanced to this position there must be a token behind 42 | // eslint-disable-next-line @typescript-eslint/no-non-null-assertion 43 | return this._tokens[this._position]?.position ?? this._tokens[this._position - 1]!.position; 44 | }; 45 | 46 | public skipTo = (type: Lexemes) => { 47 | while (!this.hasReachedEnd() && this.readCurrentToken()?.type !== type){ 48 | this.advanceCursor(1); 49 | } 50 | }; 51 | } -------------------------------------------------------------------------------- /Lib/quackscript/src/parser/TerminalParser/index.ts: -------------------------------------------------------------------------------- 1 | import { ParseException } from '../../exception/ParseException'; 2 | import { DataTypeLexemes } from '../../types/Lexemes'; 3 | import { Token } from '../../types/Token'; 4 | import { DataTypeUtils } from '../../utils/dataTypes/dataTypeUtils'; 5 | import { Cursor } from '../Cursor'; 6 | import { AssignmentOperatorNode, BooleanLiteralNode, DataTypeNode, IdentifierNode, LiteralNode, MathematicalOperatorTypes, NothingLiteralNode, NumberLiteralNode, OptionalDataType, TerminatorNode, TextLiteralNode } from '../types'; 7 | 8 | export class TerminalParser { 9 | 10 | protected _cursor: Cursor; 11 | protected _errors:Array; 12 | 13 | constructor() { 14 | this._cursor = new Cursor([]); 15 | this._errors = []; 16 | } 17 | 18 | /* 19 | := 🦆 20 | */ 21 | protected terminator = (): TerminatorNode | null => { 22 | const token = this._cursor.readCurrentToken(); 23 | 24 | if (token && token.type === 'TERMINATOR') { 25 | this._cursor.advanceCursor(1); 26 | const result: TerminatorNode = { 27 | type: 'Terminator', 28 | value: '🦆', 29 | position: token.position 30 | }; 31 | return result; 32 | } 33 | return null; 34 | }; 35 | 36 | /* 37 | := + | - | * | % | && | || | < | <= | > | >= | == | != 38 | */ 39 | protected operator = () => { 40 | const token = this._cursor.readCurrentToken(); 41 | if (!token) return null; 42 | 43 | if (this.isOperator(token)){ 44 | this._cursor.advanceCursor(1); 45 | return token.value as MathematicalOperatorTypes; 46 | } 47 | 48 | return null; 49 | }; 50 | 51 | /* 52 | := <- 53 | */ 54 | protected assignMentOperator = (): AssignmentOperatorNode | null => { 55 | const token = this._cursor.readCurrentToken(); 56 | if (!token || token.type !== 'ASSIGNMENT_OPERATOR') return null; 57 | this._cursor.advanceCursor(1); 58 | const node:AssignmentOperatorNode = { 59 | type: 'AssignmentOperator', 60 | value: token.value, 61 | position: token.position 62 | }; 63 | return node; 64 | }; 65 | 66 | /* 67 | := | | | | | ; 68 | */ 69 | protected literal = ():LiteralNode | null => { 70 | const token = this._cursor.readCurrentToken(); 71 | if (!token) return null; 72 | 73 | if (token.type === 'NUMBER_VALUE'){ 74 | this._cursor.advanceCursor(1); 75 | const value:NumberLiteralNode = { 76 | type: 'NumberLiteral', 77 | value: Number(token.value), 78 | position: token.position, 79 | }; 80 | return value; 81 | } 82 | 83 | if (token.type === 'TEXT_VALUE'){ 84 | this._cursor.advanceCursor(1); 85 | const value:TextLiteralNode = { 86 | type: 'TextLiteral', 87 | value: token.value, 88 | position: token.position 89 | }; 90 | return value; 91 | } 92 | 93 | if (token.type === 'BOOLEAN_VALUE'){ 94 | this._cursor.advanceCursor(1); 95 | if ( 96 | token.value !== 'true' && 97 | token.value !== 'false') { 98 | throw new Error('Internal error'); 99 | } 100 | const value = token.value === 'true'; 101 | const literalValue:BooleanLiteralNode = { 102 | type: 'BooleanLiteral', 103 | value: value, 104 | position: token.position 105 | }; 106 | return literalValue; 107 | } 108 | 109 | if (token.type === 'NOTHING'){ 110 | this._cursor.advanceCursor(1); 111 | const value: NothingLiteralNode = { 112 | type: 'NothingLiteral', 113 | position: token.position 114 | }; 115 | return value; 116 | } 117 | 118 | // TODO - add vector literals 119 | 120 | return null; 121 | }; 122 | 123 | /* 124 | := string 125 | */ 126 | protected identifier = () => { 127 | const token = this._cursor.readCurrentToken(); 128 | 129 | if (!token || token.type !== 'IDENTIFIER') return null; 130 | const node:IdentifierNode = { 131 | type: 'Identifier', 132 | value: token.value, 133 | position: token.position 134 | }; 135 | this._cursor.advanceCursor(1); 136 | return node; 137 | }; 138 | 139 | // := 140 | protected optionalDataType = (): OptionalDataType | null => { 141 | const lessThanToken = this._cursor.readCurrentToken(); 142 | if (lessThanToken?.type !== 'LESS_THAN') return null; 143 | this._cursor.advanceCursor(1); 144 | 145 | const type = this.dataType(); 146 | if (!type) throw new ParseException(lessThanToken.position, 'Expected data type'); 147 | 148 | const moreThanToken = this._cursor.readCurrentToken(); 149 | if (moreThanToken?.type !== 'GREATER_THAN') { 150 | throw new ParseException(moreThanToken?.position ?? type.position, `Expected > but found ${moreThanToken?.value ?? 'EOF'}`); 151 | } 152 | this._cursor.advanceCursor(1); 153 | 154 | return { 155 | internalType: type.value, 156 | position: lessThanToken.position, 157 | type: 'DataType', 158 | value: 'optional' 159 | }; 160 | }; 161 | 162 | protected dataType = (): DataTypeNode | null => { 163 | const possibleDataType = this._cursor.readCurrentToken(); 164 | if (!possibleDataType) return null; 165 | 166 | if (possibleDataType.type === 'OPTIONAL_TYPE'){ 167 | this._cursor.advanceCursor(1); 168 | return this.optionalDataType(); 169 | } 170 | if (!(possibleDataType.type in DataTypeUtils.lexemeToDataTypeMap)) { 171 | return null; 172 | } 173 | 174 | this._cursor.advanceCursor(1); 175 | const dataType = DataTypeUtils.lexemeToDataTypeMap[possibleDataType.type as DataTypeLexemes]; 176 | return { 177 | type: 'DataType', 178 | value: dataType, 179 | position: possibleDataType.position 180 | }; 181 | }; 182 | 183 | // := | 184 | protected dataTypeDeclaration = (): DataTypeNode | null => { 185 | const token = this._cursor.readCurrentToken(); 186 | if (token?.type !== 'COLON') return null; 187 | this._cursor.advanceCursor(1); 188 | const value = this.dataType(); 189 | 190 | if (!value) { 191 | throw new ParseException(token.position, `Expected data type but found ${this._cursor.readCurrentToken()?.value}`); 192 | } 193 | return value; 194 | }; 195 | 196 | protected isOperator = (token: Token) => ( 197 | token.type === 'ADDITION' || 198 | token.type === 'SUBTRACTION' || 199 | token.type === 'MULTIPLICATION' || 200 | token.type === 'MODULUS' || 201 | token.type === 'DIVISION' || 202 | token.type === 'AND' || 203 | token.type === 'OR' || 204 | token.type === 'LESS_THAN' || 205 | token.type === 'GREATER_THAN' || 206 | token.type === 'LESS_THAN_OR_EQUALS' || 207 | token.type === 'GREATER_THAN_OR_EQUALS' || 208 | token.type === 'EQUALS' || 209 | token.type === 'NOT_EQUALS' 210 | ); 211 | } -------------------------------------------------------------------------------- /Lib/quackscript/src/parser/types.ts: -------------------------------------------------------------------------------- 1 | import { Position } from '../types/Position'; 2 | 3 | export type LiteralNodeTypes = 'TextLiteral' | 4 | 'NumberLiteral' | 5 | 'NothingLiteral' | 6 | 'Vector2Literal' | 7 | 'Vector3Literal' | 8 | 'BooleanLiteral'; 9 | 10 | export type NodeTypes = LiteralNodeTypes | 11 | 'OptionalValue' | 12 | 'AccessorExpression' | 13 | 'UnaryExpression' | 14 | 'ImportStatement' | 15 | 'IfStatement' | 16 | 'BinaryExpression' | 17 | 'Expression' | 18 | 'Module' | 19 | 'Terminator' | 20 | 'Identifier' | 21 | 'AssignmentOperator' | 22 | 'Assignment' | 23 | 'Declaration' | 24 | 'Statement' | 25 | 'Return' | 26 | 'Args' | 27 | 'Param' | 28 | 'Params' | 29 | 'FuncCallNode' | 30 | 'CodeBlock' | 31 | 'FuncDeclaration' | 32 | 'InternalFuncDeclaration' | 33 | 'ReturnStatement' | 34 | 'DataType'; 35 | 36 | export type DataTypes = 'boolean' | 'text' | 'nothing' | 37 | 'vector2' | 'vector3' | 'func' | 'list' | 'number' | 'optional'; 38 | 39 | export type UnaryOperatorTypes = '!' | '-'; 40 | export type MathematicalOperatorTypes = '+' | '-' | '/' | '%' | '*'; 41 | export type ComparisonOperatorTypes = '==' | '>=' | '>' | '<' | '<=' | '!='; 42 | export type LogicalOperatorTypes = '&&' | '||'; 43 | export type OperatorTypes = MathematicalOperatorTypes | ComparisonOperatorTypes | LogicalOperatorTypes; 44 | 45 | export interface Node { 46 | type: T, 47 | position: Position 48 | } 49 | 50 | export interface IdentifierNode extends Node<'Identifier'> { 51 | value: string; 52 | } 53 | 54 | export interface ExpressionNode extends Node<'Expression'> { 55 | body: BinaryExpressionNode | LiteralNode | IdentifierNode | FuncCallNode | FuncDeclarationNode | AccessorExpressionNode 56 | } 57 | 58 | export interface AccessorExpressionNode extends Node<'AccessorExpression'> { 59 | expression: ExpressionNode, 60 | value: IdentifierNode | FuncCallNode 61 | } 62 | 63 | export interface AssignmentOperatorNode extends Node<'AssignmentOperator'> { 64 | value: string; 65 | } 66 | 67 | export interface AssignmentNode extends Node<'Assignment'> { 68 | identifier: IdentifierNode, 69 | expression: ExpressionNode 70 | } 71 | 72 | export interface DeclarationNode extends Node<'Declaration'> { 73 | declaratorType: 'constant' | 'variable', 74 | isOptional: boolean, 75 | dataType: DataTypeNode | null, 76 | assignmentNode: AssignmentNode, 77 | } 78 | 79 | export interface StatementNode extends Node<'Statement'> { 80 | body: DeclarationNode | AssignmentNode | ExpressionNode | ReturnStatementNode | IfStatementNode | ImportStatementNode 81 | } 82 | 83 | export interface ModuleNode extends Node<'Module'> { 84 | statements: Array 85 | } 86 | 87 | export interface ArgsNode extends Node<'Args'> { 88 | args: Array, 89 | } 90 | 91 | /* Declaration */ 92 | export interface ParamNode extends Node<'Param'> { 93 | identifier: IdentifierNode, 94 | dataType: DataTypeNode 95 | } 96 | 97 | export interface ParamsNode extends Node<'Params'> { 98 | params: Array, 99 | } 100 | 101 | export interface FuncCallNode extends Node<'FuncCallNode'> { 102 | params: ArgsNode | null, 103 | identifier: IdentifierNode, 104 | } 105 | 106 | export interface GenericFuncDeclarationNode extends Node<'FuncDeclaration' | 'InternalFuncDeclaration'> { 107 | parameters: ParamsNode | null, 108 | } 109 | 110 | export interface FuncDeclarationNode extends GenericFuncDeclarationNode { 111 | type: 'FuncDeclaration', 112 | body: CodeBlockNode 113 | } 114 | 115 | export interface InternalFuncDeclarationNode extends GenericFuncDeclarationNode { 116 | type: 'InternalFuncDeclaration', 117 | identifier: string, 118 | } 119 | 120 | export interface CodeBlockNode extends Node<'CodeBlock'> { 121 | // extra -> return 122 | body: Array 123 | } 124 | 125 | export interface ReturnStatementNode extends Node<'ReturnStatement'> { 126 | value: ExpressionNode 127 | } 128 | 129 | export interface IfStatementNode extends Node<'IfStatement'> { 130 | condition: ExpressionNode, 131 | trueExpression: CodeBlockNode, 132 | falseExpression: CodeBlockNode | null 133 | } 134 | 135 | export interface ImportStatementNode extends Node<'ImportStatement'> { 136 | value: TextLiteralNode 137 | } 138 | 139 | /** Terminal Nodes **/ 140 | export interface DataTypeNode extends Node<'DataType'> { 141 | value: DataTypes, 142 | } 143 | 144 | export interface OptionalDataType extends DataTypeNode { 145 | value: 'optional', 146 | internalType: DataTypes 147 | } 148 | 149 | export interface TerminatorNode extends Node<'Terminator'> { 150 | value: '🦆'; 151 | } 152 | 153 | export type LiteralNode = Node; 154 | 155 | export type NothingLiteralNode = LiteralNode<'NothingLiteral'>; 156 | 157 | export interface BooleanLiteralNode extends LiteralNode<'BooleanLiteral'> { 158 | value: boolean 159 | } 160 | 161 | export interface NumberLiteralNode extends LiteralNode<'NumberLiteral'> { 162 | value: number 163 | } 164 | 165 | export interface TextLiteralNode extends LiteralNode<'TextLiteral'> { 166 | value: string 167 | } 168 | 169 | export interface Vector2LiteralNode extends LiteralNode<'Vector2Literal'> { 170 | x: NumberLiteralNode, 171 | y: NumberLiteralNode 172 | } 173 | 174 | export interface Vector3LiteralNode extends Vector2LiteralNode { 175 | z: NumberLiteralNode, 176 | } 177 | 178 | export interface BinaryExpressionNode extends Node<'BinaryExpression'> { 179 | left: LiteralNode | IdentifierNode, 180 | right: ExpressionNode, 181 | operator: OperatorTypes 182 | } 183 | 184 | export interface UnaryExpressionNode extends Node<'UnaryExpression'> { 185 | value: LiteralNode | IdentifierNode, 186 | operator: UnaryOperatorTypes, 187 | } -------------------------------------------------------------------------------- /Lib/quackscript/src/stdLibrary/standardLibrary.ts: -------------------------------------------------------------------------------- 1 | import { DataTypes, InternalFuncDeclarationNode, TextLiteralNode } from '../parser/types'; 2 | import { Memory } from '../interpreter/memory'; 3 | import { MemoryValue, Value } from '../interpreter/types'; 4 | import { Position } from '../types/Position'; 5 | import { System } from '../system'; 6 | import { MemoryUtils } from '../utils/memory/memoryUtils'; 7 | import { RuntimeException } from '../exception/RuntimeException'; 8 | 9 | 10 | const fakePosition:Position = { 11 | globalChar: 0, 12 | line: 0, 13 | lineChar: 0 14 | }; 15 | 16 | export const executeInternalFunc = (node: InternalFuncDeclarationNode, 17 | memory: Memory, 18 | system: System): Value => { 19 | switch (node.identifier){ 20 | case 'quackprint': 21 | return execQuackPrint(memory, system); 22 | } 23 | 24 | return { 25 | type: 'NothingLiteral', 26 | position: fakePosition 27 | }; 28 | }; 29 | 30 | const execQuackPrint = (memory: Memory, system: System): Value => { 31 | const value = memory.get('value'); 32 | if (value.type !== 'text') throw new RuntimeException(fakePosition, `Invalid type, expecting Text but found ${value.type}`); 33 | system.stdout((value.value as TextLiteralNode).value); 34 | return { type: 'NothingLiteral', position: fakePosition }; 35 | }; 36 | 37 | const _standardLibrary: Array<{ 38 | identifier: string, 39 | params: Array<{ identifier: string, dataType: DataTypes }> 40 | }> = [ 41 | { identifier: 'quackprint', params: [{ 42 | dataType: 'text', 43 | identifier: 'value' 44 | }] }, 45 | ]; 46 | 47 | const standardLibrary: Record = _standardLibrary 48 | .map((value) => MemoryUtils.convertToInternalFunc(value.identifier, value.params)) 49 | .reduce((a, b) => ({ ...a, [b.identifier]: b }), {}); 50 | 51 | export default standardLibrary; -------------------------------------------------------------------------------- /Lib/quackscript/src/stdLibrary/types.ts: -------------------------------------------------------------------------------- 1 | export const standardLibraryIdentifier = [ 2 | 'quackprint' 3 | ]; -------------------------------------------------------------------------------- /Lib/quackscript/src/system/index.ts: -------------------------------------------------------------------------------- 1 | 2 | export type OutputStream = (value: string) => void; 3 | 4 | export class System { 5 | public stdout: OutputStream; 6 | public stderr: OutputStream; 7 | private _loadFile: ((path: string) => string) | undefined; 8 | 9 | constructor( 10 | stdOut?: OutputStream, 11 | stdErr?: OutputStream, 12 | loadFile?: System['loadFile']) { 13 | this.stderr = stdErr ?? console.error; 14 | this.stdout = stdOut ?? console.log; 15 | this._loadFile = loadFile; 16 | } 17 | 18 | public loadFile = (path: string): string => { 19 | if (this._loadFile) { 20 | return this._loadFile(path); 21 | } 22 | 23 | throw new Error('not implemented'); 24 | }; 25 | } -------------------------------------------------------------------------------- /Lib/quackscript/src/types/Lexemes.ts: -------------------------------------------------------------------------------- 1 | type LogicalOperatorLexemes = 'AND' | 2 | 'OR'; 3 | 4 | type ComparisonOperatorLexemes = 'EQUALS' | 5 | 'NOT_EQUALS' | 6 | 'GREATER_THAN' | 7 | 'LESS_THAN' | 8 | 'GREATER_THAN_OR_EQUALS' | 9 | 'LESS_THAN_OR_EQUALS'; 10 | 11 | type MathematicalLexemes = 'ADDITION' | 12 | 'SUBTRACTION' | 13 | 'MULTIPLICATION' | 14 | 'MODULUS' | 15 | 'DIVISION'; 16 | 17 | export type DataTypeLexemes = 'NOTHING' | 18 | 'FUNC_TYPE' | 19 | 'BOOLEAN_TYPE' | 20 | 'TEXT_TYPE' | 21 | 'NUMBER_TYPE' | 22 | 'OPTIONAL_TYPE'; 23 | 24 | 25 | export type DataValueLexemes = 'NOTHING' | 26 | 'BOOLEAN_VALUE' | 27 | 'TEXT_VALUE' | 28 | 'NUMBER_VALUE' | 29 | 'VECTOR2' | 30 | 'VECTOR3'; 31 | 32 | export type Lexemes = LogicalOperatorLexemes | 33 | ComparisonOperatorLexemes | 34 | MathematicalLexemes | 35 | DataValueLexemes | 36 | DataTypeLexemes | 37 | 'IMPORT' | 38 | 'ASSIGNMENT_OPERATOR' | 39 | 'TERMINATOR' | 40 | 'ASSIGNMENT_LET' | 41 | 'ASSIGNMENT_CONST' | 42 | 'IDENTIFIER' | 43 | 'CURLY_BRACKET_OPEN' | 44 | 'CURLY_BRACKET_CLOSE' | 45 | 'SQUARE_BRACKET_OPEN' | 46 | 'SQUARE_BRACKET_CLOSE' | 47 | 'BRACKET_OPEN' | 48 | 'BRACKET_CLOSE' | 49 | 'COMMA' | 50 | 'IF' | 51 | 'THEN' | 52 | 'ELSE' | 53 | 'RETURN' | 54 | 'DOT' | 55 | 'QUESTION_MARK' | 56 | 'COLON' | 57 | 'WHITESPACE' | 58 | 'NEW_LINE' | 59 | 'COMMENT_SHORT' | 60 | 'COMMENT_LONG'; -------------------------------------------------------------------------------- /Lib/quackscript/src/types/Position.ts: -------------------------------------------------------------------------------- 1 | export interface Position { 2 | globalChar: number, 3 | line: number, 4 | lineChar: number 5 | } -------------------------------------------------------------------------------- /Lib/quackscript/src/types/Token.ts: -------------------------------------------------------------------------------- 1 | import { Lexemes } from './Lexemes'; 2 | import { Position } from './Position'; 3 | 4 | export interface Token { 5 | value: string, 6 | position: Position, 7 | type: Lexemes, 8 | } -------------------------------------------------------------------------------- /Lib/quackscript/src/utils/dataTypes/dataTypeUtils.ts: -------------------------------------------------------------------------------- 1 | import { Value } from '../../interpreter/types'; 2 | import { BooleanLiteralNode, DataTypes, FuncDeclarationNode, NumberLiteralNode, TextLiteralNode } from '../../parser/types'; 3 | import { DataTypeLexemes } from '../../types/Lexemes'; 4 | 5 | const valueToDataTypeMap: Record = { 6 | BooleanLiteral: 'boolean', 7 | NothingLiteral: 'nothing', 8 | NumberLiteral: 'number', 9 | TextLiteral: 'text', 10 | Vector2Literal: 'vector2', 11 | Vector3Literal: 'vector3', 12 | FuncDeclaration: 'func', 13 | InternalFuncDeclaration: 'func', 14 | OptionalValue: 'optional' 15 | }; 16 | 17 | const convertValueToText = (value: Value): TextLiteralNode => { 18 | let textValue = ''; 19 | switch (value.type) { 20 | case 'BooleanLiteral': 21 | textValue = (value as BooleanLiteralNode).value ? 'true' : 'false'; 22 | break; 23 | case 'FuncDeclaration': 24 | case 'InternalFuncDeclaration': 25 | // eslint-disable-next-line no-case-declarations 26 | const paramsAsString = ((value as FuncDeclarationNode).parameters)?.params.map((value) => ( 27 | `${value.identifier.value}:${value.dataType.value}` 28 | )).join(', ') ?? ''; 29 | textValue = `(${paramsAsString}) > { [function-body] }`; 30 | break; 31 | case 'NothingLiteral': 32 | textValue = 'nothing'; 33 | break; 34 | case 'NumberLiteral': 35 | textValue = (value as NumberLiteralNode).value.toString(); 36 | break; 37 | case 'Vector2Literal': 38 | throw new Error('conversion to string not implemented'); 39 | case 'Vector3Literal': 40 | throw new Error('conversion to string not implemented'); 41 | case 'TextLiteral': 42 | return (value as TextLiteralNode); 43 | case 'OptionalValue': 44 | textValue = `${convertValueToText(value.value).value}:Optional<${value.internalType}>`; 45 | } 46 | return { 47 | position: value.position, 48 | type: 'TextLiteral', 49 | value: textValue 50 | }; 51 | }; 52 | 53 | export const lexemeToDataTypeMap: Record = { 54 | 'BOOLEAN_TYPE': 'boolean', 55 | 'FUNC_TYPE': 'func', 56 | 'NOTHING': 'nothing', 57 | 'NUMBER_TYPE': 'number', 58 | 'OPTIONAL_TYPE': 'optional', 59 | 'TEXT_TYPE': 'text', 60 | }; 61 | 62 | export const DataTypeUtils = { 63 | valueToDataType: (nodeType: Value['type']) => ( valueToDataTypeMap[nodeType] ), 64 | convertValueToText, 65 | lexemeToDataTypeMap 66 | }; 67 | -------------------------------------------------------------------------------- /Lib/quackscript/src/utils/memory/memoryUtils.ts: -------------------------------------------------------------------------------- 1 | import { MemoryValue, } from '../../interpreter/types'; 2 | import { DataTypes, InternalFuncDeclarationNode, ParamNode } from '../../parser/types'; 3 | import { Position } from '../../types/Position'; 4 | 5 | const fakePosition:Position = { 6 | globalChar: 1, 7 | line: 1, 8 | lineChar: 1 9 | }; 10 | 11 | const convertToInternalFunc = (identifier: string, params: Array<{ 12 | identifier: string, 13 | dataType: DataTypes 14 | }>): MemoryValue => ({ 15 | internalType: null, 16 | declarationType: 'internal', 17 | identifier: identifier, 18 | type: 'internalFunc', 19 | value: { 20 | identifier: identifier, 21 | position: fakePosition, 22 | parameters: { 23 | position: fakePosition, 24 | type: 'Params', 25 | params: params.map((param) => ({ 26 | dataType: { 27 | position: fakePosition, 28 | type: 'DataType', 29 | value: param.dataType 30 | }, 31 | identifier: { 32 | position: fakePosition, 33 | type: 'Identifier', 34 | value: param.identifier 35 | }, 36 | position: fakePosition, 37 | type: 'Param' 38 | } as ParamNode)), 39 | }, 40 | type: 'InternalFuncDeclaration', 41 | } as InternalFuncDeclarationNode 42 | }); 43 | 44 | export const MemoryUtils = { 45 | convertToInternalFunc 46 | }; 47 | -------------------------------------------------------------------------------- /Lib/quackscript/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Visit https://aka.ms/tsconfig to read more about this file */ 4 | 5 | /* Projects */ 6 | // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ 7 | // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ 8 | // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */ 9 | // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ 10 | // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ 11 | // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ 12 | 13 | /* Language and Environment */ 14 | "target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ 15 | "module": "commonjs", /* Specify what module code is generated. */ 16 | // "rootDir": "./", /* Specify the root folder within your source files. */ 17 | // "moduleResolution": "node10", /* Specify how TypeScript looks up a file from a given module specifier. */ 18 | // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ 19 | // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ 20 | // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ 21 | // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ 22 | // "types": [], /* Specify type package names to be included without being referenced in a source file. */ 23 | // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ 24 | // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ 25 | // "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */ 26 | // "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */ 27 | // "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */ 28 | // "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */ 29 | // "resolveJsonModule": true, /* Enable importing .json files. */ 30 | // "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */ 31 | // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ 32 | 33 | /* JavaScript Support */ 34 | "allowJs": false, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ 35 | "checkJs": false, /* Enable error reporting in type-checked JavaScript files. */ 36 | // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ 37 | 38 | /* Emit */ 39 | // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ 40 | // "declarationMap": true, /* Create sourcemaps for d.ts files. */ 41 | // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ 42 | // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ 43 | // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ 44 | // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ 45 | // "outDir": "./", /* Specify an output folder for all emitted files. */ 46 | // "removeComments": true, /* Disable emitting comments. */ 47 | // "noEmit": true, /* Disable emitting files from a compilation. */ 48 | // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ 49 | // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */ 50 | // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ 51 | // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ 52 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ 53 | // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ 54 | // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ 55 | // "newLine": "crlf", /* Set the newline character for emitting files. */ 56 | // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */ 57 | // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */ 58 | // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ 59 | // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ 60 | // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ 61 | // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ 62 | 63 | /* Interop Constraints */ 64 | // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ 65 | // "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */ 66 | // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ 67 | "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ 68 | // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ 69 | "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ 70 | 71 | /* Type Checking */ 72 | "strict": true, /* Enable all strict type-checking options. */ 73 | "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ 74 | "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ 75 | "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ 76 | "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ 77 | "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ 78 | "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */ 79 | "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */ 80 | "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ 81 | "noUnusedLocals": false, /* Enable error reporting when local variables aren't read. */ 82 | "noUnusedParameters": false, /* Raise an error when a function parameter isn't read. */ 83 | "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ 84 | "noImplicitReturns": false, /* Enable error reporting for codepaths that do not explicitly return in a function. */ 85 | "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ 86 | "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */ 87 | "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ 88 | "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ 89 | "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ 90 | "allowUnreachableCode": false, /* Disable error reporting for unreachable code. */ 91 | 92 | /* Completeness */ 93 | // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ 94 | "skipLibCheck": true /* Skip type checking all .d.ts files. */ 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /_redirects: -------------------------------------------------------------------------------- 1 | /docs/* /out/docs/:splat 200 2 | /* /out/web/:splat 200 3 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "quackscript-mono", 3 | "version": "1.0.0", 4 | "repository": "https://github.com/Niv3K-El-Pato/QuackScript.git", 5 | "author": "Niv3k_El_Pato ", 6 | "license": "MIT", 7 | "private": true, 8 | "workspaces": [ 9 | "Apps/*", 10 | "Lib/*" 11 | ], 12 | "scripts": { 13 | "build": "yarn --cwd ./Apps/web build --outDir=../../out/web & yarn --cwd ./Apps/docs build --out-dir ../../out/docs" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # QuackScript 2 | In development, syntax *WILL* change. 3 | 4 | Webpage: https://quackscript.com 5 | 6 | Documentation: https://quackscript.com/docs --------------------------------------------------------------------------------