├── .gitignore ├── .packages ├── install_test.sh ├── linux.sh ├── osx.sh ├── scoop │ └── kitlang-prerelease.json └── windows.sh ├── .travis.yml ├── CONTRIBUTING.md ├── ISSUE_TEMPLATE.md ├── LICENSE-RUNTIME.md ├── LICENSE.md ├── README.md ├── assets ├── icon-512.png ├── icon.svg ├── logo-128.png └── logo.svg ├── bin └── kitc │ └── Main.hs ├── helloworld.kit ├── package.yaml ├── samples ├── README.md ├── hangman │ └── hangman.kit └── sdl │ └── sdl.kit ├── src ├── Kit.hs └── Kit │ ├── Ast.hs │ ├── Ast │ ├── BasicType.hs │ ├── ConcreteType.hs │ ├── ConcreteTypeBase.hs │ ├── DefStatement.hs │ ├── Definitions.hs │ ├── Definitions │ │ ├── ArgSpec.hs │ │ ├── Base.hs │ │ ├── EnumVariant.hs │ │ ├── FunctionDefinition.hs │ │ ├── RewriteRule.hs │ │ ├── TraitDefinition.hs │ │ ├── TraitImplementation.hs │ │ ├── TypeDefinition.hs │ │ └── VarDefinition.hs │ ├── Expr.hs │ ├── ExprType.hs │ ├── Identifier.hs │ ├── Metadata.hs │ ├── Modifier.hs │ ├── ModulePath.hs │ ├── Operator.hs │ ├── Span.hs │ ├── Statement.hs │ ├── TypeConstraint.hs │ ├── TypeParam.hs │ ├── TypePath.hs │ ├── TypeSpec.hs │ ├── TypeSpecBase.hs │ ├── TypeVar.hs │ ├── TypedExpr.hs │ ├── TypedStmt.hs │ ├── UsingType.hs │ └── Value.hs │ ├── Compiler.hs │ ├── Compiler │ ├── Binding.hs │ ├── Context.hs │ ├── DumpAst.hs │ ├── Generators.hs │ ├── Generators │ │ ├── C.hs │ │ └── C │ │ │ ├── CExpr.hs │ │ │ ├── CFun.hs │ │ │ ├── CTypeDecl.hs │ │ │ ├── GenerateCHeader.hs │ │ │ └── GenerateCModule.hs │ ├── Ir.hs │ ├── Ir │ │ ├── DeclarationToIr.hs │ │ ├── ExprToIr.hs │ │ ├── FindUnderlyingType.hs │ │ ├── PatternMatchToIr.hs │ │ └── StringCompare.hs │ ├── Module.hs │ ├── Passes.hs │ ├── Passes │ │ ├── BuildModuleGraph.hs │ │ ├── CompileCode.hs │ │ ├── ExpandMacros.hs │ │ ├── FlattenTraits.hs │ │ ├── GenerateCode.hs │ │ ├── GenerateIr.hs │ │ ├── GenerateMonomorphs.hs │ │ ├── IncludeCModules.hs │ │ ├── ResolveModuleTypes.hs │ │ ├── SpecializeTypes.hs │ │ └── TypeModuleContent.hs │ ├── Scope.hs │ ├── TermRewrite.hs │ ├── TypeContext.hs │ ├── Typers.hs │ ├── Typers │ │ ├── AutoRefDeref.hs │ │ ├── Base.hs │ │ ├── ConvertExpr.hs │ │ ├── ExprTyper.hs │ │ ├── TypeExpression.hs │ │ ├── TypeExpression │ │ │ ├── ExprToType.hs │ │ │ ├── TypeArrayAccess.hs │ │ │ ├── TypeCall.hs │ │ │ ├── TypeCast.hs │ │ │ ├── TypeControl.hs │ │ │ ├── TypeField.hs │ │ │ ├── TypeIdentifier.hs │ │ │ ├── TypeLiteral.hs │ │ │ ├── TypeMatch.hs │ │ │ ├── TypeOp.hs │ │ │ ├── TypeStructInit.hs │ │ │ ├── TypeVarBinding.hs │ │ │ └── TypeVarDeclaration.hs │ │ ├── TypeFunction.hs │ │ ├── TypeImpl.hs │ │ ├── TypeTrait.hs │ │ ├── TypeType.hs │ │ └── TypeVar.hs │ ├── Unify.hs │ └── Utils.hs │ ├── Error.hs │ ├── HashTable.hs │ ├── Ir.hs │ ├── Ir │ ├── IrBundle.hs │ ├── IrExpr.hs │ ├── IrModule.hs │ └── IrStmt.hs │ ├── Log.hs │ ├── NameMangling.hs │ ├── Parser.hs │ ├── Parser │ ├── Base.hs │ ├── Lexer.x │ ├── Parser.y │ └── Token.hs │ ├── Str.hs │ ├── Toolchain.hs │ └── Toolchain │ └── CCompiler.hs ├── stack.yaml ├── std ├── kit │ ├── array.kit │ ├── cmp.kit │ ├── common.kit │ ├── either.kit │ ├── hash.kit │ ├── io.kit │ ├── iterator.kit │ ├── list.kit │ ├── map.kit │ ├── math.kit │ ├── mem.kit │ ├── numeric.kit │ ├── option.kit │ ├── pointer.kit │ ├── property.kit │ ├── random.kit │ ├── result.kit │ ├── ring_buffer.kit │ ├── set.kit │ ├── slice.kit │ ├── string.kit │ ├── sys │ │ ├── dir.kit │ │ ├── file.kit │ │ ├── path.kit │ │ ├── prelude.kit │ │ └── utils.kit │ ├── utils.kit │ ├── vector.kit │ └── yaml.kit └── prelude.kit ├── tests ├── Kit │ ├── Ast │ │ ├── ExprTypeSpec.hs │ │ └── SpanSpec.hs │ ├── Compiler │ │ ├── ContextSpec.hs │ │ ├── Generators │ │ │ └── C │ │ │ │ ├── CExprSpec.hs │ │ │ │ └── CTypeDeclSpec.hs │ │ ├── Passes │ │ │ ├── BuildModuleGraphSpec.hs │ │ │ ├── IncludeCModulesSpec.hs │ │ │ └── test_header.h │ │ ├── ScopeSpec.hs │ │ └── UnifySpec.hs │ ├── CompilerSpec.hs │ └── Parser │ │ ├── LexerSpec.hs │ │ ├── ParserSpec.hs │ │ └── StdSpec.hs ├── Spec.hs ├── Test.hs └── functional │ ├── README.md │ ├── abstracts.kit │ ├── abstracts.stdout │ ├── allocation.kit │ ├── allocation.stdout │ ├── associated_types.kit │ ├── associated_types.stdout │ ├── autorefderef.kit │ ├── autorefderef.stdout │ ├── box.kit │ ├── box.stdout │ ├── c_macro_expansion.kit │ ├── c_macro_expansion.stdout │ ├── carray.kit │ ├── carray.stdout │ ├── casting.kit │ ├── casting.stdout │ ├── const.kit │ ├── const.stdout │ ├── const_type.kit │ ├── const_type.stdout │ ├── cstring.kit │ ├── cstring.stdout │ ├── defined.kit │ ├── defined.stdout │ ├── double_wildcard.kit │ ├── double_wildcard.stdout │ ├── empty.kit │ ├── enums.kit │ ├── enums.stdout │ ├── extend.kit │ ├── extend.stdout │ ├── extern.kit │ ├── for.kit │ ├── for.stdout │ ├── functions.kit │ ├── functions.stdout │ ├── generic_functions.kit │ ├── generic_functions.stdout │ ├── generic_traits.kit │ ├── generic_traits.stdout │ ├── generic_types.kit │ ├── generic_types.stdout │ ├── helloworld.kit │ ├── helloworld.stdout │ ├── identifiers.kit │ ├── identifiers.stdout │ ├── implicits.kit │ ├── implicits.stdout │ ├── inline_c.kit │ ├── inline_c.stdout │ ├── issues │ ├── issue105.kit │ ├── issue105.stdout │ ├── issue106.kit │ ├── issue106.stdout │ ├── issue111.kit │ ├── issue111.stdout │ ├── issue124.kit │ ├── issue124.stdout │ ├── issue132.kit │ ├── issue137.kit │ ├── issue137.stdout │ ├── issue14.kit │ ├── issue14.stdout │ ├── issue16.kit │ ├── issue16.stdout │ ├── issue22.kit │ ├── issue22.stdout │ ├── issue34.kit │ ├── issue34.stdout │ ├── issue35.kit │ ├── issue35.sdout │ ├── issue37.kit │ ├── issue37.stdout │ ├── issue4.kit │ ├── issue4.stdout │ ├── issue57.kit │ ├── issue6.kit │ ├── issue6.stdout │ ├── issue60.kit │ ├── issue75.kit │ ├── issue75.stdout │ ├── issue8.kit │ ├── issue80.kit │ ├── issue80.stdout │ ├── issue87.kit │ ├── issue87.stdout │ ├── issue93.kit │ ├── issue93.stdout │ ├── issue96.kit │ ├── issue96.stdout │ ├── issue97.kit │ └── issue97.stdout │ ├── literals.kit │ ├── literals.stdout │ ├── macros.kit │ ├── macros.stdout │ ├── match.kit │ ├── match.stdout │ ├── methods.kit │ ├── methods.stdout │ ├── modulevars.kit │ ├── operator.kit │ ├── operator.stdout │ ├── param_inference.kit │ ├── param_inference.stdout │ ├── pointers.kit │ ├── pointers.stdout │ ├── reserved_words.kit │ ├── reserved_words.stdout │ ├── rewrite.kit │ ├── rewrite.stdout │ ├── sizeof.kit │ ├── static_if.kit │ ├── static_if.stdout │ ├── static_init.kit │ ├── static_init.stdout │ ├── staticmethods.kit │ ├── staticmethods.stdout │ ├── std │ ├── _yaml.kit │ ├── array.kit │ ├── array.stdout │ ├── either.kit │ ├── either.stdout │ ├── iterator.kit │ ├── iterator.stdout │ ├── list.kit │ ├── list.stdout │ ├── map.kit │ ├── map.stdout │ ├── math.kit │ ├── math.stdout │ ├── mem.kit │ ├── mem.stdout │ ├── numeric.kit │ ├── numeric.stdout │ ├── option.kit │ ├── option.stdout │ ├── pointer.kit │ ├── pointer.stdout │ ├── random.kit │ ├── random.stdout │ ├── result.kit │ ├── result.stdout │ ├── ring_buffer.kit │ ├── ring_buffer.stdout │ ├── set.kit │ ├── set.stdout │ ├── slice.kit │ ├── slice.stdout │ ├── string.kit │ ├── string.stdout │ ├── sys │ │ ├── dir.kit │ │ ├── dir.stdout │ │ ├── file.kit │ │ ├── file.stdout │ │ ├── path.kit │ │ └── utils.kit │ ├── vector.kit │ ├── vector.stdout │ └── yaml.stdout │ ├── structs.kit │ ├── structs.stdout │ ├── test1 │ ├── _mod1.kit │ └── test2 │ │ └── _mod2.kit │ ├── test_header1.h │ ├── traits.kit │ ├── traits.stdout │ ├── tuples.kit │ ├── tuples.stdout │ ├── type_exprs.kit │ ├── type_exprs.stdout │ ├── typedef.kit │ ├── typedef.stdout │ ├── typeinference.kit │ ├── typeinference.stdout │ ├── unions.kit │ ├── unions.stdout │ ├── varargs.kit │ ├── varargs.stdout │ ├── while.kit │ └── while.stdout ├── toolchains ├── darwin-clang ├── darwin-gcc ├── emscripten ├── linux-clang ├── linux-gcc ├── none └── windows-mingw └── utils ├── kit.kak ├── kit.nanorc ├── kit.vim └── vscode-kitlang ├── .gitignore ├── .vscode └── launch.json ├── .vscodeignore ├── CHANGELOG.md ├── README.md ├── icon.png ├── language-configuration.json ├── package.json └── syntaxes ├── kit.YAML-tmLanguage └── kit.tmLanguage /.gitignore: -------------------------------------------------------------------------------- 1 | /.cabal-sandbox 2 | /.stack-work 3 | /cabal.sandbox.config 4 | /dist 5 | *.hi 6 | \#*\# 7 | .\#* 8 | src/Kit/Parser/Lexer.hs 9 | src/Kit/Parser/Parser.hs 10 | src/Kit/Parser/Parser.info 11 | tests/Kit/Parser/Custom 12 | kitlang.cabal 13 | assets/*.png 14 | build 15 | main 16 | .importify 17 | .vscode 18 | -------------------------------------------------------------------------------- /.packages/install_test.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ## Grab the version from package.yml 4 | VERSION=`grep -r version: package.yaml | cut -d "'" -f2` 5 | 6 | if [ "$TRAVIS_BRANCH" == "dev" ]; then 7 | FILE_VERSION=$VERSION~prerelease 8 | echo "deb https://dl.bintray.com/kitlang/kitlang-prerelease-ubuntu bionic universe" | sudo tee -a /etc/apt/sources.list.d/kitlang-prereleases.list 9 | fi 10 | 11 | if [ "$TRAVIS_BRANCH" == "master" ]; then 12 | FILE_VERSION=$VERSION 13 | echo "deb https://dl.bintray.com/kitlang/kitlang-stable-ubuntu bionic universe" | sudo tee -a /etc/apt/sources.list.d/kitlang-stable.list 14 | fi 15 | 16 | sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 379CE192D401AB61 17 | sudo apt update 18 | apt search kitlang 19 | sudo apt install kitlang=$FILE_VERSION-$TRAVIS_BUILD_NUMBER 20 | kitc --version 21 | -------------------------------------------------------------------------------- /.packages/osx.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | 4 | ## Only deploy gcc matrix item 5 | if [ "$CC" == "gcc" ]; then 6 | if [ "$TRAVIS_BRANCH" == "dev" ] || [ "$TRAVIS_BRANCH" == "master" ]; then 7 | gem install fpm 8 | 9 | VERSION=`grep -r version: package.yaml | cut -d "'" -f2` 10 | 11 | if [ "$TRAVIS_BRANCH" == "dev" ] 12 | then 13 | FILE_VERSION=$VERSION-prerelease-$TRAVIS_BUILD_NUMBER 14 | fi 15 | 16 | if [ "$TRAVIS_BRANCH" == "master" ] 17 | then 18 | FILE_VERSION=$VERSION-$TRAVIS_BUILD_NUMBER 19 | fi 20 | 21 | fpm -s dir -t osxpkg -n kitlang -v $FILE_VERSION \ 22 | --description "Kit is a programming language designed for creating concise, high performance cross-platform applications." \ 23 | --license "LGPLv3.0" \ 24 | --vendor "kitlang.org" \ 25 | --maintainer "Ben Morris " \ 26 | --url "https://kitlang.org" \ 27 | ~/.local/bin/kitc=/usr/local/bin/kitc std/=/usr/local/lib/kit toolchains/=/etc/kitlang/toolchains 28 | 29 | curl --show-error --fail -vvv -T kitlang-$FILE_VERSION.pkg -ubendmorris:$BINTRAY_API_KEY \ 30 | -H "X-Bintray-Publish: 1" -H "X-Bintray-Override: 1" \ 31 | https://api.bintray.com/content/kitlang/kitlang-macos/kitlang/$VERSION/kitlang-$FILE_VERSION.pkg 32 | fi 33 | fi 34 | -------------------------------------------------------------------------------- /.packages/scoop/kitlang-prerelease.json: -------------------------------------------------------------------------------- 1 | { 2 | "homepage": "https://www.kitlang.org/", 3 | "license": "LGPL", 4 | "version": "0.1.0-prerelease-0", 5 | "architecture": { 6 | "64bit": { 7 | "url": "https://dl.bintray.com/kitlang/kitlang-prerelease-windows/kitlang_0.1.0-prerelease-0_x86_64.zip", 8 | "hash": "a06822727a3bf665e21e0064665c8c2beb69e79f7be1c09fb788b498369930d8" 9 | } 10 | }, 11 | "bin": "kitc.exe", 12 | "checkver": { 13 | "url": "https://dl.bintray.com/kitlang/kitlang-prerelease-windows/", 14 | "re": "kitlang_(.+).zip" 15 | }, 16 | "autoupdate": { 17 | "architecture": { 18 | "64bit": { 19 | "url": "https://dl.bintray.com/kitlang/kitlang-prerelease-windows/kitlang_$version_x86_64.zip" 20 | } 21 | } 22 | }, 23 | "depends": [ 24 | "gcc" 25 | ] 26 | } -------------------------------------------------------------------------------- /.packages/windows.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | 4 | ## Only deploy gcc matrix item 5 | if [ "$CC" == "gcc" ]; then 6 | 7 | # if [ "$TRAVIS_BRANCH" == "dev" ] || [ "$TRAVIS_BRANCH" == "master" ]; then 8 | if [ "$TRAVIS_BRANCH" == "dev" ]; then 9 | ## Grab the version from package.yml 10 | VERSION=`grep -r version: package.yaml | cut -d "'" -f2` 11 | 12 | if [ "$TRAVIS_BRANCH" == "dev" ]; then 13 | FILE_VERSION=$VERSION-prerelease 14 | REPO_NAME=kitlang-prerelease 15 | fi 16 | 17 | if [ "$TRAVIS_BRANCH" == "master" ]; then 18 | FILE_VERSION=$VERSION 19 | REPO_NAME=kitlang-stable 20 | fi 21 | 22 | ## Create the Windows zip 23 | stack install --local-bin-path . kitlang:kitc 24 | zip -r kitlang_${FILE_VERSION}-${TRAVIS_BUILD_NUMBER}_x86_64.zip kitc.exe std toolchains README.md LICENSE.md LICENSE-RUNTIME.md helloworld.kit 25 | 26 | ## Deploy the zip file 27 | curl --show-error --fail -T kitlang_${FILE_VERSION}-${TRAVIS_BUILD_NUMBER}_x86_64.zip -ubendmorris:$BINTRAY_API_KEY \ 28 | -H "X-Bintray-Publish: 1" \ 29 | https://api.bintray.com/content/kitlang/$REPO_NAME-windows/kitlang/$VERSION/kitlang_${FILE_VERSION}-${TRAVIS_BUILD_NUMBER}_x86_64.zip 30 | fi 31 | fi 32 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributor Guidelines 2 | 3 | Thanks for considering contributing to Kit! Open source projects can only exist with support from contributors like you. 4 | 5 | Please remember that there are a lot of ways to contribute: in addition to code changes, we can always use better documentation, more tests, issue reports, feature suggestions, etc. 6 | 7 | ## General guidelines 8 | 9 | - Changes to the compiler source should have accompanying tests: 10 | - For standalone functionality, it makes sense to have unit tests; Kit uses [hspec](http://hackage.haskell.org/package/hspec) for this. See existing tests in the "tests/" directory for examples. Hspec tests in the tests/ directory are automatically discovered. 11 | - For testing the compiler end-to-end, Kit has functional tests in "tests/compile-src". Any kit file placed here will be automatically compiled and run, and if you place a similarly named ".stdout" file next to the kit file, the stdout of your program will be compared to this file. Failure to compile, unsuccessful exit from the program, or stdout mismatch will fail the test. Please make sure your test is deterministic and doesn't rely on things like network IO or random numbers. 12 | - To run your unit/functional tests, execute `stack run` from the root directory of the repo. 13 | 14 | - Haskell code should be formatted with [brittany](https://github.com/lspitzner/brittany). No exceptions - code style is one of the least interesting things to discuss! 15 | 16 | ## Reporting an issue 17 | 18 | - Please open an issue on GitHub and fill in all relevant information from the issue template. 19 | 20 | ## Submitting a pull request 21 | 22 | - Make sure your commits have clear and descriptive messages. 23 | - Create a fork of the repository in GitHub. 24 | - Push your new code to a branch in your fork, and make a pull request. Please give enough context so we can tell why this change should be merged, and an example of the problem it's fixing if any. 25 | - Please watch the pull request and be responsive to questions or feedback so we can merge as soon as it's ready. 26 | - Your commits may be squashed on merging to keep things simple, and maintainers may make minor changes like style cleanup and squash them into your commit. 27 | 28 | ## Making a feature request 29 | 30 | For now, please reach out on [Gitter](https://gitter.im/kitlang/kit) with questions, ideas or suggestions. 31 | -------------------------------------------------------------------------------- /ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ### **Describe the problem. What did you see? What did you expect to see?** 2 | 3 | Describe the problem here. 4 | 5 | ### **If this is a code issue, provide a minimal code example:** 6 | 7 | ```kit 8 | // put your code here 9 | ``` 10 | 11 | ### **Environment** 12 | 13 | *To help with troubleshooting, please run your Kit command with an additional `--env` flag, and paste the output here* 14 | -------------------------------------------------------------------------------- /LICENSE-RUNTIME.md: -------------------------------------------------------------------------------- 1 | The Kit standard library (all .kit files in this repository) are released under 2 | the MIT license. 3 | 4 | ### The MIT License (MIT) 5 | 6 | Copyright (c) 2018 Ben Morris 7 | 8 | Permission is hereby granted, free of charge, to any person 9 | obtaining a copy of this software and associated documentation 10 | files (the "Software"), to deal in the Software without 11 | restriction, including without limitation the rights to use, 12 | copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | copies of the Software, and to permit persons to whom the 14 | Software is furnished to do so, subject to the following 15 | conditions: 16 | 17 | The above copyright notice and this permission notice shall be 18 | included in all copies or substantial portions of the Software. 19 | 20 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 22 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 23 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 24 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 25 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 26 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 27 | OTHER DEALINGS IN THE SOFTWARE. 28 | -------------------------------------------------------------------------------- /assets/icon-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kitlang/kit/2769a7a8e51fe4466c50439d1a1ebdad0fb79710/assets/icon-512.png -------------------------------------------------------------------------------- /assets/logo-128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kitlang/kit/2769a7a8e51fe4466c50439d1a1ebdad0fb79710/assets/logo-128.png -------------------------------------------------------------------------------- /helloworld.kit: -------------------------------------------------------------------------------- 1 | function main() { 2 | puts("hello world!"); 3 | } -------------------------------------------------------------------------------- /package.yaml: -------------------------------------------------------------------------------- 1 | name: kitlang 2 | version: '0.1.0' 3 | author: Ben Morris 4 | license: LGPL 5 | license-file: LICENSE.md 6 | dependencies: 7 | - base >=4.7 8 | default-extensions: 9 | - OverloadedStrings 10 | ghc-options: -O2 -optc-O3 -funfolding-use-threshold=16 -funbox-strict-fields -fexcess-precision -optc-ffast-math -with-rtsopts=-A1G -fmax-pmcheck-iterations=10000000 11 | extra-source-files: 12 | - "**/*.h" 13 | 14 | library: 15 | source-dirs: 16 | - bin 17 | - src 18 | build-tools: 19 | - alex 20 | - happy 21 | exposed-modules: 22 | - Kit 23 | - Kit.Ast 24 | - Kit.Compiler 25 | - Kit.Compiler.Generators 26 | - Kit.Compiler.Generators.C 27 | - Kit.Compiler.Ir 28 | - Kit.Compiler.Passes 29 | - Kit.Error 30 | - Kit.HashTable 31 | - Kit.Ir 32 | - Kit.Log 33 | - Kit.Parser 34 | - Kit.Str 35 | - Kit.Toolchain 36 | dependencies: 37 | - ansi-terminal 38 | - array 39 | - async 40 | - base16-bytestring 41 | - bytestring 42 | - concurrent-extra 43 | - cryptohash-md5 44 | - directory 45 | - dotenv 46 | - filepath 47 | - hashable 48 | - hashtables 49 | - language-c 50 | - mutable-containers 51 | - pretty 52 | - process 53 | - regex-posix 54 | - split 55 | - text 56 | - time 57 | - transformers 58 | - vector 59 | 60 | executables: 61 | kitc: 62 | ghc-options: -rtsopts 63 | main: Main.hs 64 | source-dirs: bin/kitc 65 | dependencies: 66 | - ansi-terminal 67 | - kitlang 68 | - optparse-applicative ==0.14.2.0 69 | - process 70 | - time 71 | 72 | tests: 73 | unit-tests: 74 | main: Test.hs 75 | source-dirs: tests 76 | ghc-options: -threaded 77 | build-tools: 78 | - alex 79 | - happy 80 | dependencies: 81 | - bytestring 82 | - directory 83 | - filepath 84 | - hspec 85 | - kitlang 86 | - language-c 87 | - mutable-containers 88 | - pretty 89 | - process 90 | - QuickCheck 91 | - temporary-rc 92 | -------------------------------------------------------------------------------- /samples/README.md: -------------------------------------------------------------------------------- 1 | To build and run any of the samples: 2 | 3 | kitc --run path/to/sample 4 | -------------------------------------------------------------------------------- /samples/sdl/sdl.kit: -------------------------------------------------------------------------------- 1 | include "SDL2/SDL.h" => "SDL2"; 2 | include "stdio.h"; 3 | 4 | function main() { 5 | var window: Ptr[SDL_Window] = null; 6 | var screenSurface: Ptr[SDL_Surface] = null; 7 | if SDL_Init(SDL_INIT_VIDEO) < 0 { 8 | panic("could not initialize sdl2: %s\n", SDL_GetError()); 9 | } 10 | window = SDL_CreateWindow( 11 | "Hello from Kit and SDL2", 12 | ${SDL_WINDOWPOS_UNDEFINED: Int}, ${SDL_WINDOWPOS_UNDEFINED: Int}, 13 | 640, 480, 14 | SDL_WINDOW_SHOWN as Uint 15 | ); 16 | if window == null { 17 | panic("could not create window: %s\n", SDL_GetError()); 18 | } 19 | screenSurface = SDL_GetWindowSurface(window); 20 | SDL_FillRect(screenSurface, null, SDL_MapRGB(screenSurface.format, 0x80, 0xff, 0xe6)); 21 | SDL_UpdateWindowSurface(window); 22 | SDL_Delay(2000); 23 | SDL_DestroyWindow(window); 24 | SDL_Quit(); 25 | } 26 | -------------------------------------------------------------------------------- /src/Kit.hs: -------------------------------------------------------------------------------- 1 | module Kit where 2 | 3 | version = "0.1.0" 4 | -------------------------------------------------------------------------------- /src/Kit/Ast.hs: -------------------------------------------------------------------------------- 1 | module Kit.Ast ( 2 | module Kit.Ast.BasicType, 3 | module Kit.Ast.ConcreteType, 4 | module Kit.Ast.Definitions, 5 | module Kit.Ast.DefStatement, 6 | module Kit.Ast.Expr, 7 | module Kit.Ast.ExprType, 8 | module Kit.Ast.Identifier, 9 | module Kit.Ast.Metadata, 10 | module Kit.Ast.Modifier, 11 | module Kit.Ast.ModulePath, 12 | module Kit.Ast.Operator, 13 | module Kit.Ast.Span, 14 | module Kit.Ast.Statement, 15 | module Kit.Ast.TypeConstraint, 16 | module Kit.Ast.TypedExpr, 17 | module Kit.Ast.TypedStmt, 18 | module Kit.Ast.TypeParam, 19 | module Kit.Ast.TypePath, 20 | module Kit.Ast.TypeSpec, 21 | module Kit.Ast.UsingType, 22 | module Kit.Ast.Value, 23 | ) where 24 | 25 | import Kit.Ast.BasicType 26 | import Kit.Ast.ConcreteType 27 | import Kit.Ast.Definitions 28 | import Kit.Ast.DefStatement 29 | import Kit.Ast.Expr 30 | import Kit.Ast.ExprType 31 | import Kit.Ast.Identifier 32 | import Kit.Ast.Metadata 33 | import Kit.Ast.Modifier 34 | import Kit.Ast.ModulePath 35 | import Kit.Ast.Operator 36 | import Kit.Ast.Span 37 | import Kit.Ast.Statement 38 | import Kit.Ast.TypeConstraint 39 | import Kit.Ast.TypedExpr 40 | import Kit.Ast.TypedStmt 41 | import Kit.Ast.TypeParam 42 | import Kit.Ast.TypePath 43 | import Kit.Ast.TypeSpec 44 | import Kit.Ast.UsingType 45 | import Kit.Ast.Value 46 | -------------------------------------------------------------------------------- /src/Kit/Ast/ConcreteType.hs: -------------------------------------------------------------------------------- 1 | module Kit.Ast.ConcreteType ( 2 | ConcreteType, 3 | ConcreteArgs, 4 | TraitConstraint, 5 | module Kit.Ast.ConcreteTypeBase 6 | ) where 7 | 8 | import Kit.Ast.ConcreteTypeBase 9 | import Kit.Ast.TypedExpr 10 | 11 | type ConcreteType = ConcreteTypeBase TypedExpr 12 | type TraitConstraint = TraitConstraintBase TypedExpr 13 | type ConcreteArgs = ConcreteArgsBase TypedExpr 14 | -------------------------------------------------------------------------------- /src/Kit/Ast/Definitions.hs: -------------------------------------------------------------------------------- 1 | module Kit.Ast.Definitions ( 2 | module Kit.Ast.Definitions.ArgSpec, 3 | module Kit.Ast.Definitions.Base, 4 | module Kit.Ast.Definitions.EnumVariant, 5 | module Kit.Ast.Definitions.FunctionDefinition, 6 | module Kit.Ast.Definitions.RewriteRule, 7 | module Kit.Ast.Definitions.TraitDefinition, 8 | module Kit.Ast.Definitions.TraitImplementation, 9 | module Kit.Ast.Definitions.TypeDefinition, 10 | module Kit.Ast.Definitions.VarDefinition 11 | ) where 12 | 13 | import Kit.Ast.Definitions.ArgSpec 14 | import Kit.Ast.Definitions.Base 15 | import Kit.Ast.Definitions.EnumVariant 16 | import Kit.Ast.Definitions.FunctionDefinition 17 | import Kit.Ast.Definitions.RewriteRule 18 | import Kit.Ast.Definitions.TraitDefinition 19 | import Kit.Ast.Definitions.TraitImplementation 20 | import Kit.Ast.Definitions.TypeDefinition 21 | import Kit.Ast.Definitions.VarDefinition 22 | -------------------------------------------------------------------------------- /src/Kit/Ast/Definitions/ArgSpec.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE DeriveGeneric #-} 2 | 3 | module Kit.Ast.Definitions.ArgSpec( 4 | ArgSpec (..), 5 | newArgSpec, 6 | convertArgSpec 7 | ) where 8 | 9 | import Control.Monad 10 | import Data.Hashable 11 | import GHC.Generics 12 | import Kit.Ast.Definitions.Base 13 | import Kit.Ast.Metadata 14 | import Kit.Ast.Modifier 15 | import Kit.Ast.TypePath 16 | import Kit.Ast.Span 17 | import Kit.Str 18 | 19 | data ArgSpec a b = ArgSpec { 20 | argName :: Str, 21 | argType :: b, 22 | argDefault :: Maybe a, 23 | argPos :: Span 24 | } deriving (Generic, Show) 25 | 26 | instance Positioned (ArgSpec a b) where 27 | position = argPos 28 | 29 | instance (Hashable a, Hashable b) => Hashable (ArgSpec a b) where 30 | hashWithSalt = hashUsing argType 31 | 32 | instance (Eq a, Eq b) => Eq (ArgSpec a b) where 33 | (==) a b = (argType a == argType b) 34 | 35 | newArgSpec = ArgSpec 36 | { argName = undefined 37 | , argType = Nothing 38 | , argDefault = Nothing 39 | , argPos = NoPos 40 | } 41 | 42 | convertArgSpec 43 | :: (Monad m) => Converter m a b c d -> ArgSpec a b -> m (ArgSpec c d) 44 | convertArgSpec (Converter { exprConverter = exprConverter, typeConverter = typeConverter }) a 45 | = do 46 | newType <- typeConverter (argPos a) (argType a) 47 | newDefault <- maybeConvert exprConverter (argDefault a) 48 | return $ newArgSpec { argName = argName a 49 | , argType = newType 50 | , argDefault = newDefault 51 | , argPos = argPos a 52 | } 53 | -------------------------------------------------------------------------------- /src/Kit/Ast/Definitions/Base.hs: -------------------------------------------------------------------------------- 1 | module Kit.Ast.Definitions.Base ( 2 | Converter (..), 3 | ParameterizedConverter (..), 4 | converter, 5 | maybeConvert 6 | ) where 7 | 8 | import Control.Monad 9 | import Kit.Ast.TypePath 10 | import Kit.Ast.Span 11 | 12 | {- 13 | Converts AST structures from m X (a b) to m X (c d), where a/c are 14 | expressions and b/d are types. 15 | -} 16 | data Converter m a b c d = Converter { 17 | exprConverter :: (a -> m c), 18 | typeConverter :: (Span -> b -> m d) 19 | } 20 | 21 | {- 22 | Converter for things (functions, types) which need to care about type 23 | parameters when resolving types. Given a list of type parameter names, will 24 | return a Converter that will handle them in type lookups. 25 | -} 26 | type ParameterizedConverter m a b c d = [TypePath] -> m (Converter m a b c d) 27 | 28 | converter e t = Converter {exprConverter = e, typeConverter = t} 29 | 30 | maybeConvert :: (Monad m) => (a -> m b) -> Maybe a -> m (Maybe b) 31 | maybeConvert converter val = do 32 | case val of 33 | Just v -> do 34 | converted <- converter v 35 | return $ Just converted 36 | Nothing -> return Nothing 37 | -------------------------------------------------------------------------------- /src/Kit/Ast/Definitions/EnumVariant.hs: -------------------------------------------------------------------------------- 1 | module Kit.Ast.Definitions.EnumVariant ( 2 | EnumVariant (..), 3 | newEnumVariant, 4 | convertEnumVariant, 5 | discriminantFieldName, 6 | variantFieldName, 7 | variantIsSimple 8 | ) where 9 | 10 | import Control.Monad 11 | import Kit.Ast.Definitions.ArgSpec 12 | import Kit.Ast.Definitions.Base 13 | import Kit.Ast.Metadata 14 | import Kit.Ast.Modifier 15 | import Kit.Ast.TypePath 16 | import Kit.Ast.Span 17 | import Kit.Str 18 | 19 | data EnumVariant a b = EnumVariant { 20 | variantName :: TypePath, 21 | variantParent :: TypePath, 22 | variantPos :: Span, 23 | variantMeta :: [Metadata], 24 | variantModifiers :: [Modifier], 25 | variantArgs :: [ArgSpec a b], 26 | variantValue :: Maybe a 27 | } deriving (Eq, Show) 28 | 29 | instance Positioned (EnumVariant a b) where 30 | position = variantPos 31 | 32 | variantRealName v = if hasNoMangle (variantMeta v) 33 | then ([], tpName $ variantName v) 34 | else subPath (variantParent v) (tpName $ variantName v) 35 | 36 | newEnumVariant = EnumVariant 37 | { variantName = undefined 38 | , variantParent = undefined 39 | , variantMeta = [] 40 | , variantModifiers = [] 41 | , variantArgs = [] 42 | , variantValue = Nothing 43 | , variantPos = NoPos 44 | } 45 | 46 | variantIsSimple = null . variantArgs 47 | 48 | convertEnumVariant 49 | :: (Monad m) => Converter m a b c d -> EnumVariant a b -> m (EnumVariant c d) 50 | convertEnumVariant converter@(Converter { exprConverter = exprConverter }) v = 51 | do 52 | newArgs <- forM (variantArgs v) (convertArgSpec converter) 53 | newValue <- maybeConvert exprConverter (variantValue v) 54 | return $ newEnumVariant { variantName = variantName v 55 | , variantParent = variantParent v 56 | , variantMeta = variantMeta v 57 | , variantModifiers = variantModifiers v 58 | , variantArgs = newArgs 59 | , variantValue = newValue 60 | , variantPos = variantPos v 61 | } 62 | 63 | discriminantFieldName :: Str 64 | discriminantFieldName = "__dsc" 65 | 66 | variantFieldName :: Str 67 | variantFieldName = "__var" 68 | -------------------------------------------------------------------------------- /src/Kit/Ast/Definitions/RewriteRule.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE DeriveGeneric #-} 2 | 3 | module Kit.Ast.Definitions.RewriteRule ( 4 | RewriteRule (..), 5 | newRewriteRule, 6 | convertRewriteRule, 7 | RuleSet (..), 8 | newRuleSet, 9 | convertRuleSet 10 | ) where 11 | 12 | import Control.Monad 13 | import Data.Hashable 14 | import GHC.Generics 15 | import Kit.Ast.Definitions.Base 16 | import Kit.Ast.TypePath 17 | import Kit.Ast.Span 18 | import Kit.Str 19 | 20 | data RewriteRule a b = RewriteRule { 21 | rulePattern :: a, 22 | ruleBody :: Maybe a, 23 | rulePos :: Span, 24 | ruleThis :: Maybe a 25 | } deriving (Eq, Generic, Show) 26 | 27 | instance Positioned (RewriteRule a b) where 28 | position = rulePos 29 | 30 | instance (Hashable a, Hashable b) => Hashable (RewriteRule a b) 31 | 32 | newRewriteRule = RewriteRule 33 | { rulePattern = undefined 34 | , ruleBody = Nothing 35 | , rulePos = NoPos 36 | , ruleThis = Nothing 37 | } 38 | 39 | convertRewriteRule 40 | :: (Monad m) => Converter m a b c d -> RewriteRule a b -> m (RewriteRule c d) 41 | convertRewriteRule converter r = do 42 | pattern <- (exprConverter converter) $ rulePattern r 43 | body <- maybeConvert (exprConverter converter) $ ruleBody r 44 | this <- maybeConvert (exprConverter converter) $ ruleThis r 45 | return $ (newRewriteRule) { rulePattern = pattern 46 | , ruleBody = body 47 | , rulePos = rulePos r 48 | , ruleThis = this 49 | } 50 | 51 | data RuleSet a b = RuleSet { 52 | ruleSetName :: TypePath, 53 | ruleSetPos :: Span, 54 | ruleSetRules :: [RewriteRule a b] 55 | } deriving (Eq, Show) 56 | 57 | instance Positioned (RuleSet a b) where 58 | position = ruleSetPos 59 | 60 | newRuleSet = RuleSet 61 | { ruleSetName = undefined 62 | , ruleSetPos = NoPos 63 | , ruleSetRules = [] 64 | } 65 | 66 | convertRuleSet 67 | :: (Monad m) => Converter m a b c d -> RuleSet a b -> m (RuleSet c d) 68 | convertRuleSet converter r = do 69 | rules <- forM (ruleSetRules r) $ convertRewriteRule converter 70 | return $ (newRuleSet) { ruleSetName = ruleSetName r 71 | , ruleSetPos = ruleSetPos r 72 | , ruleSetRules = rules 73 | } 74 | -------------------------------------------------------------------------------- /src/Kit/Ast/Definitions/VarDefinition.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE DeriveGeneric #-} 2 | 3 | module Kit.Ast.Definitions.VarDefinition where 4 | 5 | import Control.Monad 6 | import Data.Hashable 7 | import GHC.Generics 8 | import Kit.Ast.Definitions.Base 9 | import Kit.Ast.Metadata 10 | import Kit.Ast.Modifier 11 | import Kit.Ast.TypePath 12 | import Kit.Ast.Span 13 | import Kit.Str 14 | 15 | data VarDefinition a b = VarDefinition { 16 | varName :: TypePath, 17 | varBundle :: Maybe TypePath, 18 | varPos :: Span, 19 | varMeta :: [Metadata], 20 | varModifiers :: [Modifier], 21 | varType :: b, 22 | varDefault :: Maybe a, 23 | varIsLocal :: Bool, 24 | varIsConst :: Bool 25 | } deriving (Eq, Generic, Show) 26 | 27 | instance Positioned (VarDefinition a b) where 28 | position = varPos 29 | 30 | instance (Hashable a, Hashable b) => Hashable (VarDefinition a b) 31 | 32 | varRealName f = 33 | if hasNoMangle (varMeta f) then ([], tpName $ varName f) else varName f 34 | 35 | newVarDefinition :: VarDefinition a b 36 | newVarDefinition = VarDefinition 37 | { varName = undefined 38 | , varBundle = Nothing 39 | , varMeta = [] 40 | , varModifiers = [Public] 41 | , varType = undefined 42 | , varDefault = Nothing 43 | , varPos = NoPos 44 | , varIsLocal = False 45 | , varIsConst = False 46 | } 47 | 48 | convertVarDefinition 49 | :: (Monad m) 50 | => Converter m a b c d 51 | -> VarDefinition a b 52 | -> m (VarDefinition c d) 53 | convertVarDefinition (Converter { exprConverter = exprConverter, typeConverter = typeConverter }) v 54 | = do 55 | newType <- typeConverter (varPos v) (varType v) 56 | newDefault <- maybeConvert exprConverter (varDefault v) 57 | return $ (newVarDefinition) { varName = varName v 58 | , varBundle = varBundle v 59 | , varMeta = varMeta v 60 | , varModifiers = varModifiers v 61 | , varType = newType 62 | , varDefault = newDefault 63 | , varPos = varPos v 64 | , varIsLocal = varIsLocal v 65 | , varIsConst = varIsConst v 66 | } 67 | -------------------------------------------------------------------------------- /src/Kit/Ast/Expr.hs: -------------------------------------------------------------------------------- 1 | {-# OPTIONS_GHC -fwarn-incomplete-patterns #-} 2 | {-# LANGUAGE DeriveGeneric #-} 3 | {-# LANGUAGE UndecidableInstances #-} 4 | 5 | module Kit.Ast.Expr where 6 | 7 | import Data.Hashable 8 | import GHC.Generics 9 | import Kit.Ast.ExprType 10 | import Kit.Ast.Span 11 | import Kit.Ast.Statement 12 | import Kit.Ast.TypeSpec 13 | 14 | type SyntacticStatement = Statement Expr TypeSpec 15 | type SyntacticExprType = ExprType Expr TypeSpec 16 | 17 | data Expr = Expr {expr :: SyntacticExprType, pos :: Span} deriving (Show, Generic) 18 | instance Eq Expr where 19 | (==) a b = (expr a) == (expr b) 20 | instance Hashable Expr where 21 | hashWithSalt = hashUsing expr 22 | 23 | ePos = pos 24 | 25 | e :: SyntacticExprType -> Expr 26 | e et = ep et NoPos 27 | 28 | ep :: SyntacticExprType -> Span -> Expr 29 | ep et p = Expr {expr = et, pos = p} 30 | 31 | pe :: Span -> SyntacticExprType -> Expr 32 | pe p et = ep et p 33 | 34 | me :: Span -> Expr -> Expr 35 | me p ex = Expr {expr = expr ex, pos = p} 36 | 37 | instance Positioned Expr where 38 | position = pos 39 | -------------------------------------------------------------------------------- /src/Kit/Ast/Identifier.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE DeriveGeneric #-} 2 | 3 | module Kit.Ast.Identifier where 4 | 5 | import Data.Hashable 6 | import GHC.Generics 7 | import Kit.Ast.TypePath 8 | import Kit.Str 9 | 10 | data Identifier b 11 | -- A variable name 12 | = Var TypePath 13 | -- A macro variable with optional type annotation: 14 | -- `$abc` or `${abc: Int}` 15 | | MacroVar Str b 16 | | Hole 17 | deriving (Eq, Generic) 18 | 19 | instance Show (Identifier b) where 20 | show (Var s) = s_unpack $ showTypePath s 21 | show (MacroVar s _) = "$" ++ s_unpack s 22 | show Hole = "_" 23 | 24 | instance (Hashable b) => Hashable (Identifier b) 25 | 26 | convertIdentifier :: (Monad m) => (b -> m d) -> Identifier b -> m (Identifier d) 27 | convertIdentifier typeConverter id = case id of 28 | Var s -> return $ Var s 29 | MacroVar s t -> do 30 | t <- typeConverter t 31 | return $ MacroVar s t 32 | Hole -> return Hole 33 | -------------------------------------------------------------------------------- /src/Kit/Ast/Metadata.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE DeriveGeneric #-} 2 | 3 | module Kit.Ast.Metadata where 4 | 5 | import Data.Hashable 6 | import GHC.Generics 7 | import Kit.Ast.Value 8 | import Kit.Str 9 | 10 | data Metadata = Metadata {metaName :: Str, metaArgs :: [MetaArg]} deriving (Eq, Generic, Show) 11 | 12 | data MetaArg 13 | = MetaIdentifier Str 14 | | MetaLiteral ValueLiteral 15 | deriving (Eq, Generic, Show) 16 | 17 | instance Hashable Metadata 18 | instance Hashable MetaArg 19 | 20 | meta s = Metadata {metaName = s, metaArgs = []} 21 | metaExtern = "extern" :: Str 22 | metaExpose = "expose" :: Str 23 | metaBuiltin = "builtin" :: Str 24 | -- "promote" allows base types to be used as their abstract type 25 | metaPromote = "promote" :: Str 26 | -- "demote" allows abstract types to unify strictly with their base type 27 | metaDemote = "demote" :: Str 28 | metaNoreturn = "noreturn" :: Str 29 | metaConst = "const" :: Str 30 | metaStatic = "static" :: Str 31 | 32 | hasMeta :: Str -> [Metadata] -> Bool 33 | hasMeta s [] = False 34 | hasMeta s (h : t) = if metaName h == s then True else hasMeta s t 35 | 36 | hasNoMangle metas = (hasMeta metaExtern metas) || (hasMeta metaExpose metas) 37 | -------------------------------------------------------------------------------- /src/Kit/Ast/Modifier.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE DeriveGeneric #-} 2 | 3 | module Kit.Ast.Modifier where 4 | 5 | import Data.Hashable 6 | import GHC.Generics 7 | 8 | data Modifier 9 | = Public 10 | | Private 11 | | Inline 12 | | Static 13 | deriving (Eq, Generic) 14 | 15 | instance Hashable Modifier 16 | 17 | instance Show Modifier where 18 | show Public = "public" 19 | show Private = "private" 20 | show Inline = "inline" 21 | show Static = "static" 22 | 23 | isPublic :: [Modifier] -> Bool 24 | isPublic (Public : t) = True 25 | isPublic (Private : t) = False 26 | isPublic (_ : t) = isPublic t 27 | isPublic [] = True 28 | -------------------------------------------------------------------------------- /src/Kit/Ast/ModulePath.hs: -------------------------------------------------------------------------------- 1 | module Kit.Ast.ModulePath where 2 | 3 | import Data.List 4 | import System.FilePath 5 | import Kit.Str 6 | 7 | type ModulePath = [Str] 8 | 9 | parseModulePath :: Str -> ModulePath 10 | parseModulePath s = s_split '.' s 11 | 12 | showModulePath :: ModulePath -> Str 13 | showModulePath s = s_join "." s 14 | 15 | moduleFilePath :: ModulePath -> FilePath 16 | moduleFilePath mod = replaceExtension (joinPath (map s_unpack mod)) ".kit" 17 | -------------------------------------------------------------------------------- /src/Kit/Ast/Operator.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE DeriveGeneric #-} 2 | 3 | module Kit.Ast.Operator where 4 | 5 | import Data.Hashable 6 | import GHC.Generics 7 | import Kit.Str 8 | 9 | data Operator 10 | = Inc 11 | | Dec 12 | | Add 13 | | Sub 14 | | Mul 15 | | Div 16 | | Mod 17 | | Eq 18 | | Neq 19 | | Gte 20 | | Lte 21 | | LeftShift 22 | | RightShift 23 | | Gt 24 | | Lt 25 | | And 26 | | Or 27 | | BitAnd 28 | | BitOr 29 | | BitXor 30 | | Invert 31 | | InvertBits 32 | | Cons 33 | | Ref 34 | | Deref 35 | | Assign 36 | | AssignOp Operator 37 | | Custom Str 38 | deriving (Eq, Generic) 39 | 40 | instance Hashable Operator 41 | 42 | instance Show Operator where 43 | show op = case op of 44 | Inc -> "++" 45 | Dec -> "--" 46 | Add -> "+" 47 | Sub -> "-" 48 | Mul -> "*" 49 | Div -> "/" 50 | Mod -> "%" 51 | Eq -> "==" 52 | Neq -> "!=" 53 | Gte -> ">=" 54 | Lte -> "<=" 55 | LeftShift -> "<<<" 56 | RightShift -> ">>>" 57 | Gt -> ">" 58 | Lt -> "<" 59 | And -> "&&" 60 | Or -> "||" 61 | BitAnd -> "&" 62 | BitOr -> "|" 63 | BitXor -> "^" 64 | Invert -> "!" 65 | InvertBits -> "~" 66 | Cons -> "::" 67 | Ref -> "&" 68 | Deref -> "*" 69 | Assign -> "=" 70 | AssignOp op -> "=" ++ (show op) 71 | Custom op -> "custom operator" 72 | -------------------------------------------------------------------------------- /src/Kit/Ast/Span.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE DeriveGeneric #-} 2 | {-# LANGUAGE PatternSynonyms #-} 3 | 4 | module Kit.Ast.Span where 5 | 6 | import Control.Applicative 7 | import Data.Hashable 8 | import GHC.Generics 9 | import System.FilePath 10 | import Kit.Ast.TypePath 11 | import Kit.Str 12 | 13 | data SpanLocation 14 | = FileSpan FilePath 15 | deriving (Eq, Generic) 16 | 17 | instance Hashable SpanLocation 18 | instance Show SpanLocation where 19 | show (FileSpan fp) = fp 20 | 21 | data Span = Span 22 | { file :: SpanLocation 23 | , startLine :: Int 24 | , startCol :: Int 25 | , endLine :: Int 26 | , endCol :: Int 27 | } deriving (Generic) 28 | 29 | pattern NoPos :: Span 30 | pattern NoPos = Span {file = FileSpan "", startLine = 0, startCol = 0, endLine = 0, endCol = 0} 31 | 32 | instance Eq Span where 33 | (==) NoPos _ = True 34 | (==) _ NoPos = True 35 | (==) (a@Span {}) (b@Span {}) = (file a == file b) && (startLine a == startLine b) && (startCol a == startCol b) && (endLine a == endLine b) && (endCol a == endCol b) 36 | 37 | instance Show Span where 38 | show NoPos = "@(???)" 39 | show span = "@" ++ show (file span) ++ 40 | ":" ++ (show $ startLine span) ++ ":" ++ (show $ startCol span) ++ 41 | (if (startCol span /= endCol span) || (startLine span /= endLine span) 42 | then "-" ++ (if startLine span /= endLine span then (show $ endLine span) ++ ":" else "") ++ (show $ endCol span) 43 | else "") 44 | 45 | instance Hashable Span 46 | 47 | class Positioned a where 48 | position :: a -> Span 49 | 50 | sp :: FilePath -> Int -> Int -> Int -> Int -> Span 51 | sp f a b c d = sp' (FileSpan f) a b c d 52 | 53 | sp' :: SpanLocation -> Int -> Int -> Int -> Int -> Span 54 | sp' f a b c d = Span 55 | { file = f 56 | , startLine = a 57 | , startCol = b 58 | , endLine = c 59 | , endCol = d 60 | } 61 | 62 | (<+>) span1 NoPos = span1 63 | (<+>) NoPos span2 = span2 64 | (<+>) span1 span2 = Span 65 | { file = file span1 66 | , startLine = fst min 67 | , startCol = snd min 68 | , endLine = fst max 69 | , endCol = snd max 70 | } 71 | where 72 | a1 = (startLine span1, startCol span1) 73 | a2 = (endLine span1, endCol span1) 74 | b1 = (startLine span2, startCol span2) 75 | b2 = (endLine span2, endCol span2) 76 | min = if a1 < b1 then a1 else b1 77 | max = if a2 > b2 then a2 else b2 78 | -------------------------------------------------------------------------------- /src/Kit/Ast/Statement.hs: -------------------------------------------------------------------------------- 1 | module Kit.Ast.Statement where 2 | 3 | import Data.Maybe 4 | import Kit.Ast.ConcreteType 5 | import Kit.Ast.Definitions 6 | import Kit.Ast.DefStatement 7 | import Kit.Ast.ModulePath 8 | import Kit.Ast.TypePath 9 | import Kit.Ast.TypeSpec 10 | import Kit.Ast.UsingType 11 | import Kit.Ast.Span 12 | import Kit.Str 13 | 14 | data ImportType = ImportSingle | ImportWildcard | ImportDoubleWildcard deriving (Eq, Show) 15 | 16 | data Statement a b = Statement {stmt :: StatementType a b, stmtPos :: Span} deriving (Eq, Show) 17 | 18 | data StatementType a b 19 | = VarDeclaration (VarDefinition a b) 20 | | FunctionDeclaration (FunctionDefinition a b) 21 | | TypeDeclaration (TypeDefinition a b) 22 | | TraitDeclaration (TraitDefinition a b) 23 | | ExtendDefinition b [DefStatement a b] 24 | | Implement (TraitImplementation a b) 25 | | TraitDefault TypeSpec TypeSpec 26 | | RuleSetDeclaration (RuleSet a b) 27 | | Typedef TypePath TypeSpec 28 | | Import ModulePath ImportType 29 | | Include FilePath (Maybe Str) 30 | | ModuleUsing (UsingType a b) 31 | | MacroDeclaration (FunctionDefinition a b) 32 | | MacroCall TypePath [a] 33 | | TupleDeclaration b 34 | | StaticInit a 35 | deriving (Eq, Show) 36 | 37 | makeStmt st = Statement {stmt = st, stmtPos = NoPos} 38 | 39 | ps :: (Eq a, Eq b) => Span -> StatementType a b -> Statement a b 40 | ps p st = Statement {stmt = st, stmtPos = p} 41 | 42 | varDecl v = ps (varPos v) $ VarDeclaration v 43 | functionDecl v = ps (functionPos v) $ FunctionDeclaration v 44 | typeDecl v = ps (typePos v) $ TypeDeclaration v 45 | traitDecl v = ps (traitPos v) $ TraitDeclaration v 46 | implDecl v = ps (implPos v) $ Implement v 47 | -------------------------------------------------------------------------------- /src/Kit/Ast/TypeParam.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE DeriveGeneric #-} 2 | 3 | module Kit.Ast.TypeParam where 4 | 5 | import Control.Monad 6 | import Data.Hashable 7 | import Data.List 8 | import GHC.Generics 9 | import Kit.Ast.Definitions.Base 10 | import Kit.Ast.TypePath 11 | import Kit.Ast.TypeSpecBase 12 | import Kit.Ast.Value 13 | import Kit.Ast.Span 14 | import Kit.Str 15 | 16 | data TypeParam b = TypeParam { 17 | paramName :: Str, 18 | typeParamPos :: Span, 19 | constraints :: [b], 20 | typeParamIsConstant :: Bool, 21 | typeParamDefault :: Maybe b 22 | } deriving (Eq, Generic, Show) 23 | 24 | instance (Hashable b) => Hashable (TypeParam b) 25 | 26 | makeTypeParam :: Str -> TypeParam b 27 | makeTypeParam s = TypeParam 28 | { paramName = s 29 | , typeParamPos = NoPos 30 | , constraints = [] 31 | , typeParamIsConstant = False 32 | , typeParamDefault = Nothing 33 | } 34 | typeParamToSpec (TypeParam { paramName = s }) = makeTypeSpec s 35 | 36 | convertTypeParam 37 | :: (Monad m) => Converter m a b c d -> TypeParam b -> m (TypeParam d) 38 | convertTypeParam converter param = do 39 | constraints <- forM (constraints param) 40 | $ typeConverter converter (typeParamPos param) 41 | def <- maybeConvert (typeConverter converter $ typeParamPos param) 42 | (typeParamDefault param) 43 | return $ (makeTypeParam $ paramName param) 44 | { typeParamPos = typeParamPos param 45 | , constraints = constraints 46 | , typeParamIsConstant = typeParamIsConstant param 47 | , typeParamDefault = def 48 | } 49 | -------------------------------------------------------------------------------- /src/Kit/Ast/TypePath.hs: -------------------------------------------------------------------------------- 1 | module Kit.Ast.TypePath where 2 | 3 | import Kit.Ast.ModulePath 4 | import Kit.Str 5 | 6 | -- FIXME: there's some bending over backwards to ise these lists in the 7 | -- "wrong" direction; would be better to reverse the namespace list 8 | 9 | -- (Optional module path or empty, type name) 10 | type TypePath = (ModulePath, Str) 11 | showTypePath ([], s) = s 12 | showTypePath (mp, s) = s_concat [showModulePath mp, ".", s] 13 | 14 | tpName (_, s) = s 15 | tpNamespace (n, _) = n 16 | subPath (tp, n) s = (tp ++ [n], s) 17 | 18 | addNamespace :: ModulePath -> TypePath -> TypePath 19 | addNamespace n (_, s) = (n, s) 20 | 21 | tpShift ([], s) = ([], s) 22 | tpShift (n , s) = let (h : t) = reverse n in (reverse t, h) 23 | 24 | modulePathToTypePath :: ModulePath -> TypePath 25 | modulePathToTypePath mod = let (h : t) = reverse mod in (reverse t, h) 26 | 27 | tpExtend (m, s) s2 = (m, s_concat [s, s2]) 28 | -------------------------------------------------------------------------------- /src/Kit/Ast/TypeSpec.hs: -------------------------------------------------------------------------------- 1 | module Kit.Ast.TypeSpec ( 2 | module Kit.Ast.TypeSpecBase, 3 | TypeSpec, 4 | ) where 5 | 6 | import Kit.Ast.TypeSpecBase 7 | import Kit.Ast.ConcreteType 8 | 9 | type TypeSpec = TypeSpecBase ConcreteType 10 | -------------------------------------------------------------------------------- /src/Kit/Ast/TypeVar.hs: -------------------------------------------------------------------------------- 1 | module Kit.Ast.TypeVar where 2 | 3 | type TypeVar = Int 4 | -------------------------------------------------------------------------------- /src/Kit/Ast/TypedExpr.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE DeriveGeneric #-} 2 | {-# LANGUAGE FlexibleInstances #-} 3 | 4 | module Kit.Ast.TypedExpr ( 5 | TypedExpr(..), 6 | TypedExprType, 7 | makeExprTyped, 8 | makeBlock 9 | ) where 10 | 11 | import Data.Hashable 12 | import GHC.Generics 13 | import Kit.Ast.ConcreteTypeBase 14 | import Kit.Ast.Definitions 15 | import Kit.Ast.ExprType 16 | import Kit.Ast.Span 17 | import Kit.Ast.Value 18 | 19 | type ConcreteType = ConcreteTypeBase TypedExpr 20 | 21 | type TypedExprType = ExprType TypedExpr ConcreteType 22 | data TypedExpr = TypedExpr { 23 | tExpr :: TypedExprType, 24 | inferredType :: ConcreteType, 25 | tImplicits :: [TypedExpr], 26 | tPos :: Span, 27 | rewrittenBy :: Maybe (RewriteRule TypedExpr ConcreteType), 28 | tIsLvalue :: Bool, 29 | tIsLocal :: Bool, 30 | tIsLocalPtr :: Bool, 31 | tCompileTimeValue :: Maybe ValueLiteral, 32 | tIsConst :: Bool, 33 | tImplicitRules :: [RewriteRule TypedExpr ConcreteType] 34 | } deriving (Generic) 35 | 36 | instance Eq TypedExpr where 37 | (==) a b = (tExpr a == tExpr b) 38 | 39 | instance Show TypedExpr where 40 | show x = "(" ++ (show $ tExpr x) ++ "): " ++ (show $ inferredType x) 41 | 42 | instance Positioned TypedExpr where 43 | position = tPos 44 | 45 | instance Hashable TypedExpr where 46 | hashWithSalt = hashUsing tExpr 47 | 48 | makeExprTyped :: TypedExprType -> ConcreteType -> Span -> TypedExpr 49 | makeExprTyped et t pos = TypedExpr 50 | { tExpr = et 51 | , inferredType = t 52 | , tImplicits = [] 53 | , tPos = pos 54 | , rewrittenBy = Nothing 55 | , tIsLvalue = False 56 | , tIsLocal = False 57 | , tIsLocalPtr = False 58 | , tCompileTimeValue = Nothing 59 | , tIsConst = False 60 | , tImplicitRules = [] 61 | } 62 | 63 | makeBlock :: TypedExpr -> TypedExpr 64 | makeBlock ex@(TypedExpr { tExpr = Block _ }) = ex 65 | makeBlock ex = makeExprTyped (Block [ex]) TypeVoid (tPos ex) 66 | -------------------------------------------------------------------------------- /src/Kit/Ast/TypedStmt.hs: -------------------------------------------------------------------------------- 1 | module Kit.Ast.TypedStmt where 2 | 3 | import Kit.Ast.ConcreteType 4 | import Kit.Ast.Statement 5 | import Kit.Ast.TypedExpr 6 | 7 | type TypedStmt = Statement TypedExpr ConcreteType 8 | -------------------------------------------------------------------------------- /src/Kit/Ast/UsingType.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE DeriveGeneric #-} 2 | 3 | module Kit.Ast.UsingType where 4 | 5 | import Data.Hashable 6 | import GHC.Generics 7 | import Kit.Ast.Definitions.Base 8 | import Kit.Ast.Span 9 | 10 | data UsingType a b 11 | = UsingRuleSet b 12 | | UsingImplicit a 13 | deriving (Eq, Generic) 14 | 15 | instance (Show a, Show b) => Show (UsingType a b) where 16 | show (UsingRuleSet b) = "rules " ++ show b 17 | show (UsingImplicit x) = "implicit " ++ show x 18 | 19 | instance (Hashable a, Hashable b) => Hashable (UsingType a b) 20 | 21 | convertUsingType 22 | :: (Monad m) => Converter m a b c d -> Span -> UsingType a b -> m (UsingType c d) 23 | convertUsingType (Converter { exprConverter = exprConverter, typeConverter = typeConverter }) pos u 24 | = case u of 25 | UsingRuleSet x -> do 26 | x' <- typeConverter pos x 27 | return $ UsingRuleSet x' 28 | UsingImplicit x -> do 29 | x' <- exprConverter x 30 | return $ UsingImplicit x' 31 | -------------------------------------------------------------------------------- /src/Kit/Ast/Value.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE DeriveGeneric #-} 2 | 3 | module Kit.Ast.Value where 4 | 5 | import Data.Hashable 6 | import GHC.Generics 7 | import Kit.Str 8 | 9 | data ValueLiteral 10 | = BoolValue Bool 11 | | IntValue Int 12 | | FloatValue Str 13 | | StringValue Str 14 | deriving (Eq, Generic) 15 | 16 | instance Hashable ValueLiteral 17 | 18 | instance Show ValueLiteral where 19 | show (BoolValue b) = if b then "true" else "false" 20 | show (IntValue i) = show i 21 | show (FloatValue s) = s_unpack s 22 | show (StringValue s) = show $ s_unpack s 23 | 24 | valueEq :: ValueLiteral -> ValueLiteral -> Bool 25 | valueEq (BoolValue a) (BoolValue b) = a == b 26 | valueEq (IntValue a) (IntValue b) = a == b 27 | valueEq (FloatValue a) (FloatValue b) = a == b 28 | -- valueEq (IntValue a) (FloatValue b) = a == b 29 | -- valueEq (FloatValue a) (IntValue b) = a == b 30 | valueEq (StringValue a) (StringValue b) = a == b 31 | valueEq _ _ = False 32 | 33 | valueIsNumber (IntValue a) = True 34 | -- valueIsNumber (FloatValue a) = True 35 | valueIsNumber _ = False 36 | 37 | valueNumber :: ValueLiteral -> Int 38 | valueNumber (IntValue a) = a 39 | 40 | instance Num ValueLiteral where 41 | (IntValue x) + (IntValue y) = IntValue (x + y) 42 | (IntValue x) - (IntValue y) = IntValue (x - y) 43 | (IntValue x) * (IntValue y) = IntValue (x * y) 44 | fromInteger x = IntValue $ fromInteger x 45 | abs (IntValue x) = IntValue $ abs x 46 | signum (IntValue x) = IntValue $ abs x 47 | 48 | instance Fractional ValueLiteral where 49 | (IntValue x) / (IntValue y) = IntValue (x `quot` y) 50 | -- fromRational (IntValue x) = IntValue $ fromRational $ fromInteger x 51 | -- fromRational (FloatValue x) = FloatValue $ fromRational x 52 | -------------------------------------------------------------------------------- /src/Kit/Compiler/Binding.hs: -------------------------------------------------------------------------------- 1 | module Kit.Compiler.Binding where 2 | 3 | import Kit.Ast 4 | 5 | {- 6 | Bindings are used as part of each Module's interface; they map names to type 7 | definitions, of which none of the types have been resolved yet. This allows 8 | other modules to look up the type and find a type variable to reference, 9 | which should eventually resolve to the correct type. 10 | 11 | Types in these bindings will be type variables; expressions are meaningless. 12 | -} 13 | data Binding a b 14 | = VarBinding (VarDefinition a b) 15 | | FunctionBinding (FunctionDefinition a b) 16 | | TypeBinding (TypeDefinition a b) 17 | | TraitBinding (TraitDefinition a b) 18 | | EnumConstructor (EnumVariant a b) 19 | | RuleSetBinding (RuleSet a b) 20 | | ExprBinding a 21 | | ModuleBinding TypePath 22 | | TypedefBinding TypeSpec ModulePath Span 23 | | MacroBinding TypePath Span 24 | deriving (Show, Eq) 25 | 26 | bindingPos (VarBinding x ) = varPos x 27 | bindingPos (FunctionBinding x ) = functionPos x 28 | bindingPos (TypeBinding x ) = typePos x 29 | bindingPos (TraitBinding x ) = traitPos x 30 | bindingPos (EnumConstructor x ) = variantPos x 31 | bindingPos (RuleSetBinding x ) = ruleSetPos x 32 | bindingPos (ExprBinding x ) = position x 33 | bindingPos (ModuleBinding _ ) = NoPos 34 | bindingPos (TypedefBinding _ _ pos) = pos 35 | bindingPos (MacroBinding tp pos ) = pos 36 | 37 | bindingIsPublic binding = case binding of 38 | VarBinding v -> isPublic (varModifiers v) 39 | FunctionBinding f -> isPublic (functionModifiers f) 40 | _ -> True 41 | 42 | type SyntacticBinding = Binding Expr TypeSpec 43 | type TypedBinding = Binding TypedExpr ConcreteType 44 | -------------------------------------------------------------------------------- /src/Kit/Compiler/Generators.hs: -------------------------------------------------------------------------------- 1 | {- 2 | This package contains code generation utilities; currently the only compile 3 | target is C. 4 | -} 5 | module Kit.Compiler.Generators ( 6 | module Kit.Compiler.Generators.C 7 | ) where 8 | 9 | import Kit.Compiler.Generators.C 10 | -------------------------------------------------------------------------------- /src/Kit/Compiler/Generators/C.hs: -------------------------------------------------------------------------------- 1 | module Kit.Compiler.Generators.C ( 2 | module Kit.Compiler.Generators.C.CExpr, 3 | module Kit.Compiler.Generators.C.CFun, 4 | module Kit.Compiler.Generators.C.CTypeDecl, 5 | module Kit.Compiler.Generators.C.GenerateCHeader, 6 | module Kit.Compiler.Generators.C.GenerateCModule 7 | ) where 8 | 9 | import Kit.Compiler.Generators.C.CExpr 10 | import Kit.Compiler.Generators.C.CFun 11 | import Kit.Compiler.Generators.C.CTypeDecl 12 | import Kit.Compiler.Generators.C.GenerateCHeader 13 | import Kit.Compiler.Generators.C.GenerateCModule 14 | -------------------------------------------------------------------------------- /src/Kit/Compiler/Generators/C/CFun.hs: -------------------------------------------------------------------------------- 1 | module Kit.Compiler.Generators.C.CFun (cfunDecl, cfunDef) where 2 | 3 | import Data.Maybe 4 | import Language.C 5 | import Kit.Ast 6 | import Kit.Compiler.Generators.C.CExpr 7 | import Kit.NameMangling 8 | import Kit.Ir 9 | import Kit.Str 10 | 11 | cfunDecl :: FunctionDefinition IrExpr BasicType -> CDecl 12 | cfunDecl f@(FunctionDefinition { functionName = name, functionType = rt, functionArgs = args, functionVararg = vararg }) 13 | = u $ CDecl 14 | ((specFromMeta $ functionMeta f) ++ typeSpec) 15 | [ ( Just $ u $ CDeclr 16 | (Just $ cIdent $ mangleName name) 17 | ( (u $ CFunDeclr (Right (map cfunArg args, isJust vararg)) []) 18 | : derivedDeclr 19 | ) 20 | Nothing 21 | (attributesFromMeta $ functionMeta f) 22 | , Nothing 23 | , Nothing 24 | ) 25 | ] 26 | where (typeSpec, derivedDeclr) = ctype rt 27 | 28 | cfunDef :: FunctionDefinition IrExpr BasicType -> CFunDef 29 | cfunDef f@(FunctionDefinition { functionName = name, functionType = rt, functionArgs = args, functionVararg = vararg, functionBody = Just body }) 30 | = u $ CFunDef 31 | ((specFromMeta $ functionMeta f) ++ typeSpec) 32 | (u $ CDeclr 33 | (Just $ cIdent $ mangleName name) 34 | ( (u $ CFunDeclr (Right (map cfunArg args, isJust vararg)) []) 35 | : derivedDeclr 36 | ) 37 | Nothing 38 | [] 39 | ) 40 | [] 41 | (transpileStmt body) 42 | where (typeSpec, derivedDeclr) = ctype rt 43 | 44 | cfunArg :: ArgSpec IrExpr BasicType -> CDecl 45 | cfunArg arg = cDecl (argType arg) (Just ([], argName arg)) Nothing 46 | 47 | attributesFromMeta :: [Metadata] -> [CAttr] 48 | attributesFromMeta (h : t) = case metaName h of 49 | "inline" -> 50 | (u $ CAttr (internalIdent "always_inline") []) : attributesFromMeta t 51 | "noreturn" -> 52 | (u $ CAttr (internalIdent "noreturn") []) : attributesFromMeta t 53 | _ -> attributesFromMeta t 54 | attributesFromMeta [] = [] 55 | 56 | specFromMeta :: [Metadata] -> [CDeclSpec] 57 | specFromMeta (h : t) = case metaName h of 58 | "extern" -> (CStorageSpec $ u $ CExtern) : specFromMeta t 59 | "static" -> (CStorageSpec $ u $ CStatic) : specFromMeta t 60 | _ -> specFromMeta t 61 | specFromMeta [] = [] 62 | -------------------------------------------------------------------------------- /src/Kit/Compiler/Ir.hs: -------------------------------------------------------------------------------- 1 | {- 2 | This package is used during Kit.Compiler.Passes.GenerateIr to generate IR and 3 | BasicTypes from typed expressions and ConcreteTypes. 4 | -} 5 | module Kit.Compiler.Ir ( 6 | module Kit.Compiler.Ir.FindUnderlyingType, 7 | module Kit.Compiler.Ir.DeclarationToIr, 8 | module Kit.Compiler.Ir.ExprToIr, 9 | module Kit.Compiler.Ir.PatternMatchToIr, 10 | module Kit.Compiler.Ir.StringCompare 11 | ) where 12 | 13 | import Kit.Compiler.Ir.FindUnderlyingType 14 | import Kit.Compiler.Ir.DeclarationToIr 15 | import Kit.Compiler.Ir.ExprToIr 16 | import Kit.Compiler.Ir.PatternMatchToIr 17 | import Kit.Compiler.Ir.StringCompare 18 | -------------------------------------------------------------------------------- /src/Kit/Compiler/Ir/StringCompare.hs: -------------------------------------------------------------------------------- 1 | module Kit.Compiler.Ir.StringCompare where 2 | 3 | import Kit.Ast 4 | import Kit.Ir 5 | import Kit.Str 6 | 7 | stringCompare :: IrExpr -> Str -> IrExpr 8 | stringCompare ex s = IrBinop 9 | Eq 10 | (IrCall 11 | (IrIdentifier ([], "strcmp")) 12 | [ ex 13 | , IrLiteral (StringValue s) (CPtr BasicTypeCChar) 14 | ] 15 | ) 16 | (IrLiteral (IntValue 0) BasicTypeCInt) 17 | -------------------------------------------------------------------------------- /src/Kit/Compiler/Module.hs: -------------------------------------------------------------------------------- 1 | module Kit.Compiler.Module where 2 | 3 | import Control.Monad 4 | import Data.Mutable 5 | import Data.Maybe 6 | import Kit.Ast 7 | import Kit.Error 8 | import Kit.HashTable 9 | import Kit.Log 10 | import Kit.Ast.Span 11 | import Kit.Str 12 | 13 | data DuplicateDeclarationError = DuplicateDeclarationError ModulePath Str Span Span deriving (Eq, Show) 14 | instance Errable DuplicateDeclarationError where 15 | logError e@(DuplicateDeclarationError mod name pos1 pos2) = do 16 | logErrorBasic e $ "Duplicate declaration for `" ++ s_unpack name ++ "` in " ++ s_unpack (showModulePath mod) ++ "; \n\nFirst declaration:" 17 | ePutStrLn "\nSecond declaration:" 18 | displayFileSnippet pos2 19 | ePutStrLn "\nFunction, variable, type and trait names must be unique within the same namespace." 20 | errPos (DuplicateDeclarationError _ _ pos _) = Just pos 21 | 22 | data Module = Module { 23 | modPath :: !ModulePath, 24 | modSourcePath :: FilePath, 25 | modImports :: ![(ModulePath, Span)], 26 | modIncludes :: IORef [(FilePath, Span)], 27 | modDefaults :: IORef [((TypeSpec, TypeSpec), Span)], 28 | modUsing :: IORef [UsingType TypedExpr ConcreteType], 29 | modIsCModule :: !Bool 30 | } 31 | 32 | instance Show Module where 33 | show m = "" 34 | 35 | newMod :: ModulePath -> FilePath -> IO Module 36 | newMod path fp = do 37 | defaults <- newRef [] 38 | includes <- newRef [] 39 | using <- newRef [] 40 | return $ Module 41 | { modPath = path 42 | , modSourcePath = fp 43 | , modImports = [] 44 | , modIncludes = includes 45 | , modDefaults = defaults 46 | , modUsing = using 47 | , modIsCModule = False 48 | } 49 | 50 | emptyMod = newMod [] undefined 51 | 52 | externModPath :: ModulePath 53 | externModPath = [] 54 | 55 | newCMod :: IO Module 56 | newCMod = do 57 | mod <- newMod externModPath "(extern)" 58 | return $ mod { modIsCModule = True } 59 | 60 | -- includeToModulePath :: FilePath -> ModulePath 61 | -- includeToModulePath fp = "extern" : (map s_pack $ splitDirectories (fp -<.> "")) 62 | 63 | modImplicits :: Module -> IO [TypedExpr] 64 | modImplicits mod = do 65 | usings <- readRef $ modUsing mod 66 | return $ catMaybes 67 | [ case u of 68 | UsingImplicit i -> Just i 69 | _ -> Nothing 70 | | u <- usings 71 | ] 72 | 73 | modImportPaths :: Module -> [ModulePath] 74 | modImportPaths mod = (modPath mod) : ((map fst $ modImports mod) ++ [[]]) 75 | -------------------------------------------------------------------------------- /src/Kit/Compiler/Passes.hs: -------------------------------------------------------------------------------- 1 | module Kit.Compiler.Passes ( 2 | module Kit.Compiler.Passes.BuildModuleGraph, 3 | module Kit.Compiler.Passes.IncludeCModules, 4 | module Kit.Compiler.Passes.ExpandMacros, 5 | module Kit.Compiler.Passes.ResolveModuleTypes, 6 | module Kit.Compiler.Passes.FlattenTraits, 7 | module Kit.Compiler.Passes.TypeModuleContent, 8 | module Kit.Compiler.Passes.SpecializeTypes, 9 | module Kit.Compiler.Passes.GenerateMonomorphs, 10 | module Kit.Compiler.Passes.GenerateIr, 11 | module Kit.Compiler.Passes.GenerateCode, 12 | module Kit.Compiler.Passes.CompileCode 13 | ) where 14 | 15 | import Kit.Compiler.Passes.BuildModuleGraph 16 | import Kit.Compiler.Passes.IncludeCModules 17 | import Kit.Compiler.Passes.ExpandMacros 18 | import Kit.Compiler.Passes.ResolveModuleTypes 19 | import Kit.Compiler.Passes.FlattenTraits 20 | import Kit.Compiler.Passes.TypeModuleContent 21 | import Kit.Compiler.Passes.SpecializeTypes 22 | import Kit.Compiler.Passes.GenerateMonomorphs 23 | import Kit.Compiler.Passes.GenerateIr 24 | import Kit.Compiler.Passes.GenerateCode 25 | import Kit.Compiler.Passes.CompileCode 26 | -------------------------------------------------------------------------------- /src/Kit/Compiler/Passes/GenerateCode.hs: -------------------------------------------------------------------------------- 1 | module Kit.Compiler.Passes.GenerateCode (generateCode) where 2 | 3 | import Control.Monad 4 | import Data.List 5 | import Data.Maybe 6 | import System.Directory 7 | import System.IO 8 | import Text.PrettyPrint 9 | import Kit.Ast 10 | import Kit.Compiler.Generators.C 11 | import Kit.Compiler.Context 12 | import Kit.Compiler.Module 13 | import Kit.Ir 14 | 15 | {- 16 | Generates C code. 17 | 18 | Declarations are bundled into compilation units; to make dependency 19 | analysis and cross-dependencies easier, a single header is generated for the 20 | entire project and included from all c files. The header will contain type 21 | definitions and variable/function declarations. 22 | -} 23 | generateCode :: CompileContext -> [(Module, [IrBundle])] -> IO [TypePath] 24 | generateCode ctx ir = do 25 | forM_ [libDir ctx, includeDir ctx, objDir ctx] $ \d -> do 26 | exists <- doesDirectoryExist d 27 | when exists $ removeDirectoryRecursive d 28 | generateProjectHeader ctx ir 29 | names <- forM ir $ generateModule ctx 30 | return $ catMaybes $ foldr (++) [] names 31 | -------------------------------------------------------------------------------- /src/Kit/Compiler/Passes/GenerateIr.hs: -------------------------------------------------------------------------------- 1 | {-# OPTIONS_GHC -fwarn-incomplete-patterns #-} 2 | 3 | module Kit.Compiler.Passes.GenerateIr (generateIr) where 4 | 5 | import Control.Monad 6 | import Data.Mutable 7 | import Data.List 8 | import Kit.Ast 9 | import Kit.Compiler.Context 10 | import Kit.Compiler.Ir 11 | import Kit.Compiler.Module 12 | import Kit.Compiler.Utils 13 | import Kit.HashTable 14 | import Kit.Ir 15 | 16 | {- 17 | Generates declarations in interediate representation for each typed module. 18 | -} 19 | generateIr 20 | :: CompileContext -> [(Module, [TypedStmt])] -> IO [(Module, [IrBundle])] 21 | generateIr ctx modContent = do 22 | modContent <- forM modContent (generateModuleIr ctx) 23 | concreteTuples <- readRef $ ctxTuples ctx 24 | basicTuples <- forM concreteTuples $ \(mod, t) -> do 25 | mod <- getMod ctx mod 26 | t <- findUnderlyingType ctx mod Nothing t 27 | return t 28 | mod <- getMod ctx (ctxMainModule ctx) 29 | return 30 | $ ( mod 31 | , [ IrBundle ([], n) [ps NoPos $ TupleDeclaration t] 32 | | t@(BasicTypeTuple n _) <- nub basicTuples 33 | ] 34 | ) 35 | : modContent 36 | 37 | generateModuleIr 38 | :: CompileContext -> (Module, [TypedStmt]) -> IO (Module, [IrBundle]) 39 | generateModuleIr ctx (mod, decls) = do 40 | debugLog ctx $ "generating IR for " ++ show mod 41 | decls <- forM decls (generateDeclIr ctx mod) 42 | return $ (mod, (foldr (++) [] decls)) 43 | -------------------------------------------------------------------------------- /src/Kit/Compiler/Scope.hs: -------------------------------------------------------------------------------- 1 | module Kit.Compiler.Scope where 2 | 3 | import Data.Mutable 4 | import Kit.HashTable 5 | import Kit.Str 6 | 7 | data Scope a = Scope { 8 | -- bound names in this scope 9 | scopeBindings :: HashTable Str a, 10 | lastTmpVar :: IORef (Int) 11 | } 12 | 13 | -- Create a new scope. 14 | newScope :: IO (Scope a) 15 | newScope = do 16 | bindings <- h_new 17 | tmp <- newRef 0 18 | return $ Scope {scopeBindings = bindings, lastTmpVar = tmp} 19 | 20 | -- Add a new binding to this scope. 21 | bindToScope :: Scope a -> Str -> a -> IO () 22 | bindToScope scope s binding = h_insert (scopeBindings scope) s binding 23 | 24 | -- Look up a binding in this scope. 25 | resolveLocal :: Scope a -> Str -> IO (Maybe a) 26 | resolveLocal scope s = h_lookup (scopeBindings scope) s 27 | 28 | scopeHas :: Scope a -> Str -> IO Bool 29 | scopeHas scope s = h_exists (scopeBindings scope) s 30 | 31 | scopeGet :: Scope a -> Str -> IO a 32 | scopeGet scope s = h_get (scopeBindings scope) s 33 | 34 | makeTmpVar :: Scope a -> IO Str 35 | makeTmpVar scope = do 36 | last <- readRef (lastTmpVar scope) 37 | let next = last + 1 38 | writeRef (lastTmpVar scope) next 39 | return $ s_concat ["__tmp", s_pack $ show next] 40 | 41 | {- 42 | Look up a binding in a set of scopes. Prefers scopes earlier in the list. 43 | -} 44 | resolveBinding :: [Scope a] -> Str -> IO (Maybe a) 45 | resolveBinding (scope : scopes) s = do 46 | x <- resolveLocal scope s 47 | case x of 48 | Just _ -> return x 49 | Nothing -> resolveBinding scopes s 50 | resolveBinding [] s = do 51 | return Nothing 52 | 53 | resolveBindingScope :: [(b, Scope a)] -> Str -> IO (Maybe b) 54 | resolveBindingScope ((b, scope) : scopes) s = do 55 | x <- resolveLocal scope s 56 | case x of 57 | Just _ -> return (Just b) 58 | Nothing -> resolveBindingScope scopes s 59 | resolveBindingScope [] s = do 60 | return Nothing 61 | 62 | -- Returns the list of bindings this scope contains. 63 | bindingList :: Scope a -> IO [a] 64 | bindingList s = do 65 | bindings <- h_toList $ scopeBindings s 66 | return $ map snd bindings 67 | 68 | -- Returns the list of bindings this scope contains. 69 | bindingNames :: Scope a -> IO [Str] 70 | bindingNames s = do 71 | bindings <- h_toList $ scopeBindings s 72 | return $ map fst bindings 73 | -------------------------------------------------------------------------------- /src/Kit/Compiler/Typers.hs: -------------------------------------------------------------------------------- 1 | {- 2 | These modules are used to refine ConcreteTypes based on language semantics. 3 | Functions generally take and return TypedExpr/ConcreteType but enforce type 4 | constraints and try to infer type variable values. 5 | -} 6 | module Kit.Compiler.Typers ( 7 | module Kit.Compiler.Typers.ConvertExpr, 8 | module Kit.Compiler.Typers.TypeExpression, 9 | module Kit.Compiler.Typers.TypeFunction, 10 | module Kit.Compiler.Typers.TypeImpl, 11 | module Kit.Compiler.Typers.TypeTrait, 12 | module Kit.Compiler.Typers.TypeType, 13 | module Kit.Compiler.Typers.TypeVar 14 | ) where 15 | 16 | import Kit.Compiler.Typers.ConvertExpr 17 | import Kit.Compiler.Typers.TypeExpression 18 | import Kit.Compiler.Typers.TypeFunction 19 | import Kit.Compiler.Typers.TypeImpl 20 | import Kit.Compiler.Typers.TypeTrait 21 | import Kit.Compiler.Typers.TypeType 22 | import Kit.Compiler.Typers.TypeVar 23 | -------------------------------------------------------------------------------- /src/Kit/Compiler/Typers/Base.hs: -------------------------------------------------------------------------------- 1 | module Kit.Compiler.Typers.Base where 2 | 3 | -------------------------------------------------------------------------------- /src/Kit/Compiler/Typers/ExprTyper.hs: -------------------------------------------------------------------------------- 1 | module Kit.Compiler.Typers.ExprTyper where 2 | 3 | import Kit.Ast 4 | import Kit.Compiler.Context 5 | import Kit.Compiler.Module 6 | import Kit.Compiler.TypeContext 7 | 8 | data TyperUtils = TyperUtils { 9 | _r :: TypedExpr -> IO TypedExpr, 10 | _tryRewrite :: TypedExpr -> IO TypedExpr -> IO TypedExpr, 11 | _resolve :: TypeConstraint -> IO (), 12 | _typeExpr :: ExprTyper, 13 | _maybeR :: Maybe TypedExpr -> IO (Maybe TypedExpr) 14 | } 15 | 16 | -- the signature of typeExpr 17 | type ExprTyper = CompileContext -> TypeContext -> Module -> TypedExpr -> IO TypedExpr 18 | -- the signature of a modular subtyper, which also receives utility functions as arguments 19 | type SubTyper = TyperUtils -> ExprTyper 20 | -------------------------------------------------------------------------------- /src/Kit/Compiler/Typers/TypeExpression/ExprToType.hs: -------------------------------------------------------------------------------- 1 | module Kit.Compiler.Typers.TypeExpression.ExprToType(exprToType) where 2 | 3 | import Control.Monad 4 | import Kit.Ast 5 | import Kit.Compiler.Context 6 | import Kit.Compiler.Module 7 | import Kit.Compiler.TypeContext 8 | 9 | exprToType 10 | :: CompileContext 11 | -> TypeContext 12 | -> Module 13 | -> Span 14 | -> TypedExpr 15 | -> IO (Maybe ConcreteType) 16 | exprToType ctx tctx mod pos ex = do 17 | let r x = exprToType ctx tctx mod pos x 18 | x <- case (tExpr ex, inferredType ex) of 19 | (_, TypeTypeOf tp params) -> return $ Just $ TypeInstance tp params 20 | (Identifier (Var s), _) -> do 21 | t <- resolveType ctx tctx mod $ TypeSpec s [] pos 22 | return $ Just t 23 | (TupleInit x, _) -> do 24 | x <- forM x $ r 25 | let result = sequence x 26 | case result of 27 | Just x -> do 28 | return $ Just $ TypeTuple x 29 | _ -> return Nothing 30 | (ArrayAccess a b, _) -> do 31 | b <- r b 32 | case b of 33 | Just b -> do 34 | a <- r a 35 | case a of 36 | Just t@(TypeInstance tp params) -> do 37 | params <- forM (params ++ [b]) $ makeGenericConcrete ctx pos 38 | return $ Just $ TypeInstance tp $ params 39 | _ -> return Nothing 40 | _ -> return Nothing 41 | (PreUnop Deref x, _) -> do 42 | x <- r x 43 | case x of 44 | Just x -> return $ Just $ TypePtr x 45 | _ -> return Nothing 46 | _ -> return Nothing 47 | case x of 48 | Just t -> genericTctx ctx tctx pos t >> return () 49 | _ -> return () 50 | return x 51 | -------------------------------------------------------------------------------- /src/Kit/Compiler/Typers/TypeExpression/TypeLiteral.hs: -------------------------------------------------------------------------------- 1 | module Kit.Compiler.Typers.TypeExpression.TypeLiteral (literalConstraints) where 2 | 3 | import Data.List 4 | import Kit.Ast 5 | import Kit.Parser 6 | 7 | {- 8 | Returns a set of type constraints for literals depending on their value. 9 | -} 10 | literalConstraints :: ValueLiteral -> ConcreteType -> Span -> [TypeConstraint] 11 | literalConstraints (BoolValue _) s pos = 12 | [TypeEq TypeBool s "Bool literal must be a Bool type" pos] 13 | literalConstraints (IntValue v) s pos = 14 | let exps = if v < 0 15 | then [-63, -53, -31, -24, -15, -7, 0] :: [Int] 16 | else [0, 7, 8, 15, 16, 24, 31, 32, 53, 63, 64] :: [Int] 17 | in 18 | let 19 | t = foldr 20 | (\(low, high) acc -> 21 | if v 22 | >= (signum low) 23 | * (2 ^ abs low) 24 | && v 25 | < (signum high) 26 | * (2 ^ abs high) 27 | then typeClassRange (if v < 0 then low else high) 28 | else acc 29 | ) 30 | typeClassNumeric 31 | (zip exps (drop 1 exps)) 32 | in [TypeEq t s "Int literals must be a Numeric type" pos] 33 | literalConstraints (FloatValue _) s pos = 34 | [ TypeEq typeClassNumericMixed 35 | s 36 | "Float literals must be a NumericMixed type" 37 | pos 38 | ] 39 | literalConstraints _ _ _ = [] 40 | -------------------------------------------------------------------------------- /src/Kit/Compiler/Typers/TypeTrait.hs: -------------------------------------------------------------------------------- 1 | module Kit.Compiler.Typers.TypeTrait where 2 | 3 | import Control.Monad 4 | import Data.List 5 | import Kit.Ast 6 | import Kit.Compiler.Context 7 | import Kit.Compiler.Module 8 | import Kit.Compiler.TypeContext 9 | import Kit.Compiler.Typers.TypeFunction 10 | import Kit.Compiler.Utils 11 | import Kit.Str 12 | 13 | {- 14 | Type checks a trait specification. 15 | -} 16 | typeTrait 17 | :: CompileContext 18 | -> TypeContext 19 | -> Module 20 | -> TraitDefinition TypedExpr ConcreteType 21 | -> IO TypedStmt 22 | typeTrait ctx tctx mod def = do 23 | debugLog ctx 24 | $ "typing trait " 25 | ++ s_unpack (showTypePath $ traitName def) 26 | ++ (case traitMonomorph def of 27 | [] -> "" 28 | x -> " monomorph " ++ show x 29 | ) 30 | typeTraitDefinition ctx tctx mod (TypeTraitConstraint (traitName def, [])) def 31 | 32 | {- 33 | Type checks a trait specification. 34 | -} 35 | typeTraitDefinition 36 | :: CompileContext 37 | -> TypeContext 38 | -> Module 39 | -> ConcreteType 40 | -> TraitDefinition TypedExpr ConcreteType 41 | -> IO TypedStmt 42 | typeTraitDefinition ctx tctx' mod selfType def = do 43 | let tctx = tctx' { tctxSelf = Just selfType, tctxThis = Just selfType } 44 | methods <- forM 45 | (traitMethods def) 46 | (\method -> do 47 | typed <- typeFunctionDefinition ctx tctx mod 48 | $ method { functionBody = Nothing } 49 | return typed 50 | ) 51 | return $ ps (traitPos def) $ TraitDeclaration $ def { traitMethods = methods } 52 | -------------------------------------------------------------------------------- /src/Kit/Compiler/Typers/TypeVar.hs: -------------------------------------------------------------------------------- 1 | module Kit.Compiler.Typers.TypeVar where 2 | 3 | import Control.Monad 4 | import Kit.Ast 5 | import Kit.Compiler.Context 6 | import Kit.Compiler.Module 7 | import Kit.Compiler.TypeContext 8 | import Kit.Compiler.Typers.TypeExpression 9 | import Kit.Compiler.Unify 10 | import Kit.Error 11 | 12 | {- 13 | Type checks a variable declaration. 14 | -} 15 | typeVar 16 | :: CompileContext 17 | -> TypeContext 18 | -> Module 19 | -> VarDefinition TypedExpr ConcreteType 20 | -> IO TypedStmt 21 | typeVar ctx tctx mod def@(VarDefinition { varName = name }) = do 22 | typed <- typeVarDefinition ctx tctx mod def 23 | return $ ps (varPos def) $ VarDeclaration typed 24 | 25 | typeVarDefinition 26 | :: CompileContext 27 | -> TypeContext 28 | -> Module 29 | -> VarDefinition TypedExpr ConcreteType 30 | -> IO (VarDefinition TypedExpr ConcreteType) 31 | typeVarDefinition ctx tctx mod def = do 32 | case varDefault def of 33 | Just x -> do 34 | typed <- typeExpr ctx tctx mod x 35 | resolveConstraint 36 | ctx 37 | tctx 38 | (TypeEq 39 | (varType def) 40 | (inferredType typed) 41 | "Variable and field default values must match the variable's type" 42 | (varPos def) 43 | ) 44 | return $ def { varDefault = Just typed } 45 | Nothing -> do 46 | when (varIsConst def) $ throwk $ TypingError 47 | ("const must have an initial value") 48 | (varPos def) 49 | return def 50 | -------------------------------------------------------------------------------- /src/Kit/HashTable.hs: -------------------------------------------------------------------------------- 1 | module Kit.HashTable where 2 | 3 | import Data.Hashable 4 | import qualified Data.HashTable.IO as H 5 | import Data.Maybe 6 | 7 | {- 8 | This typedef + methods are here to make it easier to swap out hash table 9 | implementations if necessary. 10 | -} 11 | type HashTable k v = H.LinearHashTable k v 12 | 13 | -- defaulting a bit larger so we don't have to resize as frequently 14 | h_new :: (Eq k, Hashable k) => IO (HashTable k v) 15 | h_new = H.newSized 32 16 | 17 | h_newSized :: (Eq k, Hashable k) => Int -> IO (HashTable k v) 18 | h_newSized n = H.newSized n 19 | 20 | h_insert :: (Eq k, Hashable k) => HashTable k v -> k -> v -> IO () 21 | h_insert = H.insert 22 | 23 | h_delete :: (Eq k, Hashable k) => HashTable k v -> k -> IO () 24 | h_delete = H.delete 25 | 26 | h_lookup :: (Eq k, Hashable k) => HashTable k v -> k -> IO (Maybe v) 27 | h_lookup = H.lookup 28 | 29 | h_exists :: (Eq k, Hashable k) => HashTable k v -> k -> IO (Bool) 30 | h_exists m k = do 31 | val <- h_lookup m k 32 | return $ case val of 33 | Just _ -> True 34 | Nothing -> False 35 | 36 | h_get :: (Eq k, Hashable k, Show k) => HashTable k v -> k -> IO v 37 | h_get m k = do 38 | val <- h_lookup m k 39 | return 40 | $ maybe (error $ "Unexpected missing HashTable key: " ++ show k) id 41 | $ val 42 | 43 | h_toList :: (Eq k, Hashable k) => HashTable k v -> IO [(k, v)] 44 | h_toList = H.toList 45 | 46 | h_foldM :: (Eq k, Hashable k) => (a -> (k, v) -> IO a) -> a -> HashTable k v -> IO a 47 | h_foldM = H.foldM 48 | 49 | h_mapM_ :: (Eq k, Hashable k) => ((k, v) -> IO b) -> HashTable k v -> IO () 50 | h_mapM_ = H.mapM_ 51 | -------------------------------------------------------------------------------- /src/Kit/Ir.hs: -------------------------------------------------------------------------------- 1 | module Kit.Ir ( 2 | module Kit.Ir.IrBundle, 3 | module Kit.Ir.IrStmt, 4 | module Kit.Ir.IrExpr, 5 | module Kit.Ir.IrModule 6 | ) where 7 | 8 | import Kit.Ir.IrBundle 9 | import Kit.Ir.IrStmt 10 | import Kit.Ir.IrExpr 11 | import Kit.Ir.IrModule 12 | -------------------------------------------------------------------------------- /src/Kit/Ir/IrBundle.hs: -------------------------------------------------------------------------------- 1 | module Kit.Ir.IrBundle where 2 | 3 | import Kit.Ast 4 | import Kit.Ir.IrStmt 5 | 6 | data IrBundle = IrBundle TypePath [IrStmt] 7 | 8 | bundleTp (IrBundle x _) = x 9 | bundleMembers (IrBundle _ x) = x 10 | 11 | mergeBundles x y = IrBundle (bundleTp x) (bundleMembers x ++ bundleMembers y) 12 | -------------------------------------------------------------------------------- /src/Kit/Ir/IrExpr.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE DeriveGeneric #-} 2 | 3 | module Kit.Ir.IrExpr where 4 | 5 | import Data.Hashable 6 | import GHC.Generics 7 | import Kit.Str 8 | import Kit.Ast 9 | 10 | data IrExpr 11 | = IrBlock [IrExpr] 12 | | IrCompound [IrExpr] 13 | | IrLiteral ValueLiteral BasicType 14 | | IrIdentifier TypePath 15 | | IrPreUnop Operator IrExpr 16 | | IrPostUnop Operator IrExpr 17 | | IrBinop Operator IrExpr IrExpr 18 | | IrFor Str BasicType IrExpr IrExpr IrExpr 19 | | IrWhile IrExpr IrExpr Bool 20 | | IrIf IrExpr IrExpr (Maybe IrExpr) 21 | | IrContinue 22 | | IrBreak 23 | | IrReturn (Maybe IrExpr) 24 | | IrField IrExpr Str 25 | | IrArrayAccess IrExpr IrExpr 26 | | IrCall IrExpr [IrExpr] 27 | | IrCast IrExpr BasicType 28 | | IrCArrLiteral [IrExpr] BasicType 29 | | IrVarDeclaration Str BasicType (Maybe IrExpr) 30 | | IrStructInit BasicType [(Str, IrExpr)] 31 | | IrUnionInit BasicType (Str, IrExpr) 32 | | IrEnumInit BasicType TypePath [(Str, IrExpr)] 33 | | IrTupleInit BasicType [IrExpr] 34 | | IrSizeOf BasicType 35 | | IrType BasicType 36 | | IrSwitch IrExpr [(IrExpr, IrExpr)] (Maybe IrExpr) 37 | | IrNull 38 | | IrEmpty BasicType 39 | | IrInlineC Str 40 | deriving (Eq, Show, Generic) 41 | 42 | instance Hashable IrExpr 43 | 44 | isValidInitializer (IrLiteral _ _ ) = True 45 | isValidInitializer (IrIdentifier _ ) = True 46 | isValidInitializer (IrEmpty _ ) = True 47 | isValidInitializer (IrNull ) = True 48 | isValidInitializer (IrCArrLiteral x _) = all isValidInitializer x 49 | isValidInitializer (IrCast x _) = isValidInitializer x 50 | isValidInitializer (IrStructInit _ fields) = 51 | all isValidInitializer $ map snd fields 52 | isValidInitializer (IrPreUnop Ref x ) = isValidInitializer x 53 | isValidInitializer (IrEnumInit _ _ []) = True 54 | isValidInitializer _ = False 55 | -------------------------------------------------------------------------------- /src/Kit/Ir/IrModule.hs: -------------------------------------------------------------------------------- 1 | module Kit.Ir.IrModule where 2 | 3 | import Kit.Ast 4 | import Kit.Ir.IrStmt 5 | 6 | data IrModule = IrModule { 7 | irmodPath :: ModulePath, 8 | irmod_declarations :: [IrStmt], 9 | irmodIncludes :: [FilePath] 10 | } 11 | -------------------------------------------------------------------------------- /src/Kit/Ir/IrStmt.hs: -------------------------------------------------------------------------------- 1 | module Kit.Ir.IrStmt where 2 | 3 | import Kit.Ast 4 | import Kit.Ir.IrExpr 5 | 6 | type IrStmt = Statement IrExpr BasicType 7 | -------------------------------------------------------------------------------- /src/Kit/Log.hs: -------------------------------------------------------------------------------- 1 | module Kit.Log where 2 | 3 | import Control.Monad 4 | import qualified Control.Concurrent.Lock as Lock (new, with) 5 | import Data.Time 6 | import Data.Time.Format 7 | import Data.Time.LocalTime 8 | import System.Console.ANSI 9 | import System.IO 10 | import System.IO.Unsafe 11 | 12 | data LogLevel 13 | = Notice 14 | | Debug 15 | | Warning 16 | | Error 17 | 18 | normal = SetConsoleIntensity NormalIntensity 19 | bold = SetConsoleIntensity BoldIntensity 20 | color = SetColor Foreground Vivid 21 | 22 | logColor lv = case lv of 23 | Notice -> White 24 | Debug -> Blue 25 | Warning -> Yellow 26 | Error -> Red 27 | 28 | maybeSetSGR a b = do 29 | supports <- hSupportsANSI a 30 | when supports $ hSetSGR a b 31 | 32 | logLock = unsafePerformIO (Lock.new) 33 | 34 | logPrefix :: LogLevel -> IO () 35 | logPrefix lv = do 36 | maybeSetSGR stderr [color (logColor lv), normal] 37 | case lv of 38 | Notice -> ePutStr "===> " 39 | Debug -> ePutStr "DBG: " 40 | Warning -> ePutStr "WRN: " 41 | Error -> ePutStr "ERR: " 42 | 43 | logMsg :: Maybe LogLevel -> String -> IO () 44 | logMsg lv msg = Lock.with logLock $ do 45 | maybeSetSGR stderr [color Yellow, normal] 46 | ePutStr "[" 47 | maybeSetSGR stderr [color Cyan, normal] 48 | t <- getZonedTime 49 | ePutStr $ formatTime defaultTimeLocale "%F %T.%4q" t 50 | maybeSetSGR stderr [color Yellow, normal] 51 | ePutStr "]" 52 | maybeSetSGR stderr [Reset] 53 | ePutStr " " 54 | case lv of 55 | Just lv -> logPrefix lv 56 | Nothing -> return () 57 | let intensity = case lv of 58 | Just Notice -> bold 59 | _ -> normal 60 | case lv of 61 | Just lv -> maybeSetSGR stderr [color (logColor lv), intensity] 62 | Nothing -> maybeSetSGR stderr [Reset] 63 | ePutStrLn msg 64 | maybeSetSGR stderr [Reset] 65 | hFlush stderr 66 | 67 | traceLog = logMsg Nothing 68 | printLog = logMsg (Just Notice) 69 | printDebugLog = logMsg (Just Debug) 70 | warningLog = logMsg (Just Warning) 71 | errorLog = logMsg (Just Error) 72 | 73 | ePutStr = hPutStr stderr 74 | ePutStrLn = hPutStrLn stderr 75 | -------------------------------------------------------------------------------- /src/Kit/NameMangling.hs: -------------------------------------------------------------------------------- 1 | module Kit.NameMangling where 2 | 3 | import Data.List 4 | import Data.Maybe 5 | import Kit.Ast.BasicType 6 | import Kit.Ast.ConcreteTypeBase 7 | import Kit.Ast.TypePath 8 | import Kit.Str 9 | 10 | validName :: Str -> Str 11 | validName name = 12 | if s_length name > 63 then s_concat ["kit", s_hash name] else name 13 | 14 | mangleName :: TypePath -> Str 15 | mangleName ([], s) = s 16 | mangleName (namespace, s) = 17 | validName $ s_concat [s_join "_" namespace, "__", s] 18 | 19 | monomorphName :: (Show a) => TypePath -> [ConcreteTypeBase a] -> TypePath 20 | monomorphName tp [] = tp 21 | monomorphName tp@(namespace, s) p = 22 | if null p then tp else monomorphAddSuffix tp $ Just $ monomorphSuffix p 23 | 24 | tupleName :: [BasicType] -> Str 25 | tupleName slots = s_concat ["tuple", hashParams slots] 26 | 27 | monomorphSuffix :: (Show a) => [ConcreteTypeBase a] -> Str 28 | monomorphSuffix p = hashParams p 29 | 30 | monomorphAddSuffix :: TypePath -> Maybe Str -> TypePath 31 | monomorphAddSuffix tp (Just suffix) = subPath tp suffix 32 | monomorphAddSuffix tp Nothing = tp 33 | 34 | discriminantMemberName :: TypePath -> Str 35 | discriminantMemberName discriminant = 36 | s_concat ["variant_", tpName discriminant] 37 | 38 | hashParams :: (Show a) => [a] -> Str 39 | hashParams p = s_hash $ s_concat $ map (s_pack . show) p 40 | -------------------------------------------------------------------------------- /src/Kit/Parser.hs: -------------------------------------------------------------------------------- 1 | module Kit.Parser( 2 | module Kit.Parser.Base, 3 | module Kit.Parser.Lexer, 4 | module Kit.Parser.Parser, 5 | module Kit.Ast.Span, 6 | module Kit.Parser.Token, 7 | parseString, 8 | parseFile 9 | ) where 10 | 11 | import qualified Data.ByteString.Lazy.Char8 as BL 12 | import Kit.Ast 13 | import Kit.Parser.Base 14 | import Kit.Parser.Lexer 15 | import Kit.Parser.Parser 16 | import Kit.Ast.Span 17 | import Kit.Parser.Token 18 | import Kit.Str 19 | 20 | parseString :: BL.ByteString -> Parser [SyntacticStatement] 21 | parseString s = parseTokens $ scanTokens (FileSpan "") s 22 | 23 | parseFile :: FilePath -> IO (Parser [SyntacticStatement]) 24 | parseFile f = do 25 | contents <- BL.readFile f 26 | return $ parseTokens $ scanTokens (FileSpan f) contents 27 | -------------------------------------------------------------------------------- /src/Kit/Parser/Base.hs: -------------------------------------------------------------------------------- 1 | module Kit.Parser.Base where 2 | 3 | import Kit.Error 4 | import Kit.Ast.Span 5 | 6 | data Parser a = ParseResult a | Err KitError 7 | 8 | data ParseError = ParseError String (Maybe Span) deriving (Eq, Show) 9 | instance Errable ParseError where 10 | logError err@(ParseError msg _) = logErrorBasic (KitError err) msg 11 | errPos (ParseError _ pos) = pos 12 | 13 | instance Functor Parser where 14 | fmap f (ParseResult x) = ParseResult (f x) 15 | fmap f (Err e) = Err e 16 | 17 | instance Applicative Parser where 18 | pure = ParseResult 19 | (<*>) (ParseResult f) (ParseResult x) = ParseResult (f x) 20 | (<*>) (Err e) _ = Err e 21 | (<*>) _ (Err e) = Err e 22 | 23 | instance Monad Parser where 24 | (>>=) m f = case m of 25 | ParseResult x -> f x 26 | Err e -> Err e 27 | return = ParseResult 28 | -------------------------------------------------------------------------------- /src/Kit/Str.hs: -------------------------------------------------------------------------------- 1 | module Kit.Str where 2 | 3 | import Crypto.Hash.MD5 4 | import Data.ByteString.Base16 5 | import qualified Data.ByteString.Char8 as B 6 | import qualified Data.ByteString.Lazy as BL 7 | 8 | {- 9 | This typedef + methods are here to make it easier to swap out string 10 | implementations if necessary. 11 | -} 12 | type Str = B.ByteString 13 | 14 | s_head = B.head 15 | s_pack = B.pack 16 | s_unpack = B.unpack 17 | s_length = B.length 18 | s_take = B.take 19 | s_takeWhile = B.takeWhile 20 | s_drop = B.drop 21 | s_dropWhile = B.dropWhile 22 | s_findIndices = B.findIndices 23 | s_readFile = B.readFile 24 | s_concat = B.concat 25 | s_split = B.split 26 | s_join = B.intercalate 27 | s_hash s = s_take 24 $ encode $ hash $ s 28 | s_isSuffixOf = B.isSuffixOf 29 | s_isPrefixOf = B.isPrefixOf 30 | 31 | l2s = B.concat . BL.toChunks 32 | -------------------------------------------------------------------------------- /src/Kit/Toolchain.hs: -------------------------------------------------------------------------------- 1 | module Kit.Toolchain ( 2 | module Kit.Toolchain.CCompiler, 3 | ) where 4 | 5 | import Kit.Toolchain.CCompiler 6 | -------------------------------------------------------------------------------- /stack.yaml: -------------------------------------------------------------------------------- 1 | resolver: lts-12.9 2 | -------------------------------------------------------------------------------- /std/kit/array.kit: -------------------------------------------------------------------------------- 1 | /** 2 | * Array is a heap-allocated, length-prefixed, fixed-length collection type. 3 | */ 4 | abstract Array[T]: Slice[T] { 5 | public static function new(allocator: Box[Allocator], length: Size): Self { 6 | var data: Ptr[T] = allocator.calloc(sizeof T * length); 7 | return struct Self { 8 | length, 9 | data, 10 | }; 11 | } 12 | 13 | public function blit(other: Ptr[Array[T]], start: Size, length: Size): Void { 14 | memcpy(&(other.data[start]) as Ptr[Void], this.data as Ptr[Void], length * sizeof T); 15 | } 16 | 17 | public function copy(allocator: Box[Allocator]): Array[T] using implicit allocator { 18 | var a = Self.new(this.length); 19 | this.blit(a, 0, this.length); 20 | return a; 21 | } 22 | 23 | public function free(allocator: Box[Allocator]) { 24 | allocator.free(this.data); 25 | } 26 | 27 | public function all(fn: function (&T) -> Bool): Bool { 28 | for item in this { 29 | if !fn(item) { 30 | return false; 31 | } 32 | } 33 | return true; 34 | } 35 | 36 | public function any(fn: function (&T) -> Bool): Bool { 37 | for item in this { 38 | if fn(item) { 39 | return true; 40 | } 41 | } 42 | return false; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /std/kit/cmp.kit: -------------------------------------------------------------------------------- 1 | /** 2 | * Trait for testing equality between two types. 3 | * 4 | * In some cases the logic for equality relations is built in to the compiler, 5 | * e.g. comparing numeric types, or tuples or structs of comparable types. A 6 | * relevant Eq instance will be checked for first before applying these native 7 | * comparisons. 8 | */ 9 | trait Eq[T] { 10 | /** 11 | * Tests for `this` and `other to be equal. 12 | */ 13 | public function eq(other: T): Bool; 14 | 15 | /** 16 | * Doesn't need to be implemented; any manual implementation should return 17 | * the inverse of `eq`. 18 | */ 19 | public function neq(other: T) { 20 | return !this.eq(other); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /std/kit/either.kit: -------------------------------------------------------------------------------- 1 | enum Either[A, B] { 2 | Left(a: A); 3 | Right(b: B); 4 | 5 | public function isLeft() { 6 | match this { 7 | Left(_) => return true; 8 | default => return false; 9 | } 10 | } 11 | 12 | public function isRight() { 13 | match this { 14 | Left(_) => return false; 15 | default => return true; 16 | } 17 | } 18 | 19 | // public function unwrapLeft() { 20 | // return match this { 21 | // Left(l) => l; 22 | // Right(_) => throw WrongValueError; 23 | // } 24 | // } 25 | 26 | // public function unwrapRight() { 27 | // return match this { 28 | // Left(_) => throw WrongValueError; 29 | // Right(r) => r; 30 | // } 31 | // } 32 | } 33 | -------------------------------------------------------------------------------- /std/kit/hash.kit: -------------------------------------------------------------------------------- 1 | /** 2 | * Hashable trait must be implemented for any key in the hashmap, 3 | * as the hash function is used to determine it's place in the map. 4 | */ 5 | trait Hashable { 6 | function hash(): Int; 7 | } 8 | 9 | enum HashCellState { 10 | Empty; 11 | Deleted; 12 | Occupied; 13 | } 14 | 15 | implement Hashable for Bool { 16 | function hash(): Int { 17 | return if this then 1 else 0; 18 | } 19 | } 20 | 21 | implement Hashable for CString { 22 | function hash(): Int { 23 | var hash = 5381; 24 | for char in this { 25 | hash = (hash << 5) + hash + char; 26 | } 27 | return hash; 28 | } 29 | } 30 | 31 | implement Hashable for Int { 32 | function hash(): Int { 33 | return this; 34 | } 35 | } 36 | 37 | implement Hashable for Char { 38 | function hash(): Int { 39 | return this; 40 | } 41 | } 42 | 43 | implement Hashable for String { 44 | function hash(): Int { 45 | var hash = 5381; 46 | for char in this { 47 | hash = (hash << 5) + hash + char; 48 | } 49 | return hash; 50 | } 51 | } 52 | 53 | // implement Hashable for Integral { 54 | // function hash(): Int { 55 | // return this; 56 | // } 57 | // } -------------------------------------------------------------------------------- /std/kit/io.kit: -------------------------------------------------------------------------------- 1 | /** 2 | * An abstract reader. 3 | */ 4 | trait Reader { 5 | public function readBytes(buf: Ptr[Void], bytes: Size): Size; 6 | public function close(): Void; 7 | } 8 | 9 | /** 10 | * An abstract writer. 11 | */ 12 | trait Writer { 13 | public function writeBytes(buf: Ptr[Void], bytes: Size): Size; 14 | 15 | public function write(v: Box[Writable]): Size { 16 | return this.writeBytes(v.ptr(), v.size()); 17 | } 18 | 19 | public function flush(): Void {} 20 | public function close(): Void {} 21 | } 22 | 23 | trait Writable { 24 | public function ptr(): Ptr[Void]; 25 | public function size(): Size; 26 | } 27 | 28 | implement Writable for CString { 29 | public function ptr(): Ptr[Void] { 30 | return this; 31 | } 32 | 33 | public function size(): Size { 34 | return this.length + 1; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /std/kit/math.kit: -------------------------------------------------------------------------------- 1 | var PI = 3.14159265358979323846264338327950288_f64; 2 | 3 | function max[T: Numeric](x: T, y: T): T { 4 | return if y > x then y else x; 5 | } 6 | 7 | function min[T: Numeric](x: T, y: T): T { 8 | return if y < x then y else x; 9 | } 10 | -------------------------------------------------------------------------------- /std/kit/option.kit: -------------------------------------------------------------------------------- 1 | /** 2 | * Represents a nullable value. 3 | */ 4 | enum Option[T] { 5 | Some(value: T); 6 | None; 7 | 8 | public function isSome(): Bool { 9 | match this { 10 | None => return false; 11 | default => return true; 12 | } 13 | } 14 | public function isNone(): Bool { 15 | match this { 16 | None => return true; 17 | default => return false; 18 | } 19 | } 20 | 21 | public function unwrap(): T { 22 | match this { 23 | Some(value) => return value; 24 | default => panic("unwrap: unexpected missing value"); 25 | } 26 | } 27 | 28 | public function or(other: T): T { 29 | match this { 30 | Some(v) => return v; 31 | default => return other; 32 | } 33 | } 34 | 35 | rules { 36 | ($this ?? $other) => $this.or($other); 37 | 38 | // ($this ?. $id) => if $this.isSome() then Some($this.unwrap().$id) else None; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /std/kit/pointer.kit: -------------------------------------------------------------------------------- 1 | struct RefCount { 2 | var allocator: Box[Allocator]; 3 | var count: Int = 1; 4 | } 5 | 6 | /** 7 | * A smart pointer to type T that employs reference counting. Call `ref()` to 8 | * obtain an additional reference, and `release()` when the reference is 9 | * released; the memory will be reclaimed when there are no more active 10 | * references. 11 | */ 12 | abstract Shared[T]: Ptr[T] { 13 | // public static function new(allocator: Box[Allocator]): Self { 14 | // return Self.alloc(sizeof T) as Shared[T]; 15 | // } 16 | 17 | public static function alloc(allocator: Box[Allocator], bytes: Size): Self { 18 | var ptr: Ptr[RefCount] = allocator.calloc(sizeof RefCount + bytes); 19 | ptr.count = 1; 20 | ptr.allocator = allocator; 21 | return (ptr + 1) as Self; 22 | } 23 | 24 | /** 25 | * Increment the reference count and return the pointer. 26 | */ 27 | public function ref(): Self { 28 | var meta = this.metadata(); 29 | ++meta.count; 30 | return this; 31 | } 32 | 33 | /** 34 | * Decrement the reference count. If this causes the count to drop to 0, 35 | * free it. 36 | */ 37 | public function release(): Bool { 38 | var meta = this.metadata(); 39 | if meta.count == 0 { 40 | return true; 41 | } else if --meta.count == 0 { 42 | this.free(); 43 | return true; 44 | } else { 45 | return false; 46 | } 47 | } 48 | 49 | /** 50 | * Decrement the reference count, but don't free. If this function returns 51 | * true, the user is responsible to free. 52 | */ 53 | public function decrement(): Bool { 54 | var meta = this.metadata(); 55 | if meta.count == 0 { 56 | return false; 57 | } else if --meta.count == 0 { 58 | return true; 59 | } else { 60 | return false; 61 | } 62 | } 63 | 64 | public function free() { 65 | var meta = this.metadata(); 66 | meta.allocator.free(meta); 67 | } 68 | 69 | public function active(): Bool { 70 | var meta = this.metadata(); 71 | return meta.count > 0; 72 | } 73 | 74 | public function rc(): Size { 75 | var meta = this.metadata(); 76 | return meta.count; 77 | } 78 | 79 | function metadata(): Ptr[RefCount] { 80 | return (this as Ptr[Void] as Ptr[RefCount]) - 1; 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /std/kit/property.kit: -------------------------------------------------------------------------------- 1 | macro getter(type: CString, fieldName: CString) { 2 | printf("extend %s { rule ($this.%s) => $this.get_%s(); }", type, fieldName, fieldName); 3 | } 4 | 5 | macro setter(type: CString, fieldName: CString) { 6 | printf("extend %s { rule ($this.%s = $x) => $this.set_%s($x); }", type, fieldName, fieldName); 7 | } 8 | -------------------------------------------------------------------------------- /std/kit/random.kit: -------------------------------------------------------------------------------- 1 | /** 2 | * Seed the random number generator used by `random` and `randomRange`. 3 | */ 4 | public function seed(seed: Uint) { 5 | srand(seed); 6 | } 7 | 8 | /** 9 | * Generates a random number between 0 and 1. 10 | */ 11 | public function random(): Double { 12 | return rand() as Double / ${RAND_MAX: Uint16}; 13 | } 14 | 15 | /** 16 | * Generates a random integer between min and max, inclusive. 17 | */ 18 | public function randomRange(min: Int, max: Int): Int { 19 | return min + (((1 + max - min) * random()) as Int); 20 | } 21 | -------------------------------------------------------------------------------- /std/kit/result.kit: -------------------------------------------------------------------------------- 1 | import kit.utils; 2 | 3 | enum Result[T, E] { 4 | Ok(value: T); 5 | Error(error: E); 6 | 7 | public function isOk(): Bool { 8 | match this { 9 | Ok(_) => return true; 10 | default => return false; 11 | } 12 | } 13 | 14 | public function isError(): Bool { 15 | match this { 16 | Error(_) => return true; 17 | default => return false; 18 | } 19 | } 20 | 21 | public function unwrap(): T { 22 | match this { 23 | Ok(v) => return v; 24 | default => panic("Result.unwrap"); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /std/kit/ring_buffer.kit: -------------------------------------------------------------------------------- 1 | struct RingBuffer[T] { 2 | public var length: Size; 3 | var start: Size; 4 | public var data: Array[T]; 5 | 6 | public static function new(allocator: Box[Allocator], length: Size): RingBuffer[T] { 7 | var data = Array.new(length); 8 | return struct Self { 9 | start: 0, 10 | length: 0, 11 | data, 12 | }; 13 | } 14 | 15 | public function push(value: T): T { 16 | if this.length >= this.data.length { 17 | this.start = (this.start + 1) % this.data.length; 18 | } else { 19 | ++this.length; 20 | } 21 | this[this.length - 1] = value; 22 | return value; 23 | } 24 | 25 | public function pop(): Option[T] { 26 | if this.length > 0 { 27 | --this.length; 28 | return Some(this[this.length]); 29 | } else { 30 | return None; 31 | } 32 | } 33 | 34 | rules { 35 | ($this[$index]) => $this.data[($this.start + $index) % ($this.data.length)]; 36 | 37 | (for $ident in $this {$e}) => { 38 | var __length = $this.length; 39 | for __i in 0 ... __length { 40 | var $ident = $this[__i]; 41 | {$e} 42 | } 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /std/kit/slice.kit: -------------------------------------------------------------------------------- 1 | /** 2 | * A Slice is a length-prefixed pointer to contiguous values. 3 | * 4 | * Slice is used as the base for length-prefixed types such as Array and 5 | * String. 6 | */ 7 | struct Slice[T] { 8 | public var length: Size; 9 | public var data: Ptr[T]; 10 | 11 | public function ref(): Ptr[T] { 12 | return this.data; 13 | } 14 | 15 | public function clear() { 16 | memset(this.data, 0, sizeof T * this.length); 17 | } 18 | 19 | // public function contains(value: T): Bool { 20 | // for i in 0 ... this.length { 21 | // if *(this.data + i) == value { 22 | // return true; 23 | // } 24 | // } 25 | // return false; 26 | // } 27 | 28 | rules { 29 | ($this[$i ... $j]) => struct Self {length: $j - $i, data: &$this.data[$i]}; 30 | ($this[$i]) => $this.data[$i]; 31 | ($this.unsafeLast) => $this[$this.length - 1]; 32 | 33 | // optimize Slice iteration at compile time when the type is known 34 | (for $ident in $this {$e}) => { 35 | var __length = $this.length; 36 | for __i in 0 ... __length { 37 | var $ident = $this.data[__i]; 38 | {$e} 39 | } 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /std/kit/sys/dir.kit: -------------------------------------------------------------------------------- 1 | include "dirent.h"; 2 | include "unistd.h"; 3 | include "sys/time.h"; 4 | 5 | abstract Directory: dirent { 6 | public static function read(path: Path): DirectoryReader { 7 | return DirectoryReader.new(path); 8 | } 9 | 10 | rules { 11 | ($this.path) => ($this.d_name as CString) as Path; 12 | } 13 | } 14 | 15 | abstract DirectoryReader: Ptr[DIR] { 16 | public static function new(path: Path) { 17 | return opendir(path) as DirectoryReader; 18 | } 19 | 20 | rules { 21 | (for $ident in $this {$e}) => { 22 | var __dir = $this; 23 | do { 24 | var __next: Ptr[Directory] = readdir(__dir) as Ptr[Directory]; 25 | if __next == null { 26 | break; 27 | } else { 28 | var $ident = __next; 29 | {$e} 30 | } 31 | } while true; 32 | } 33 | } 34 | } 35 | 36 | implement Iterable(Ptr[Directory]) for DirectoryReader { 37 | public function iterator(): Box[Iterator[Ptr[Directory]]] { 38 | return this; 39 | } 40 | } 41 | 42 | implement Iterator[Ptr[Directory]] for DirectoryReader { 43 | public function next(): (Box[Iterator[Ptr[Directory]]], Option[Ptr[Directory]]) { 44 | var dir = readdir(this) as Ptr[Directory]; 45 | if dir != null { 46 | return (this, Some(dir)); 47 | } else { 48 | return (this, None); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /std/kit/sys/path.kit: -------------------------------------------------------------------------------- 1 | #[promote] abstract Path: CString { 2 | // FIXME 3 | public static var PATH_SEP: Char = c'/'; 4 | 5 | rules { 6 | // (${p1: Path} / ${p2: Path}) => $p1.join($p2); 7 | } 8 | 9 | public function isAbsolute(): Bool { 10 | return this.length > 0 && this[0] == Self.PATH_SEP; 11 | } 12 | 13 | public function join(allocator: Box[Allocator], other: Path): Path { 14 | if other.isAbsolute() { 15 | return other; 16 | } else { 17 | var l1 = this.length; 18 | var l2 = other.length; 19 | var addSep = this[l1 - 1] != Self.PATH_SEP; 20 | var joined: CString = allocator.alloc(this.length + other.length + (if addSep then 2 else 1)); 21 | strncpy(joined, this, l1); 22 | if addSep { 23 | joined[l1] = Self.PATH_SEP; 24 | strcpy(joined + l1 + 1, other); 25 | } else { 26 | strcpy(joined + l1, other); 27 | } 28 | return joined; 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /std/kit/sys/prelude.kit: -------------------------------------------------------------------------------- 1 | import kit.sys.path; 2 | -------------------------------------------------------------------------------- /std/kit/sys/utils.kit: -------------------------------------------------------------------------------- 1 | include "unistd.h"; 2 | include "sys/time.h"; 3 | 4 | /** 5 | * Sleep for the specified amount of time, in seconds. 6 | */ 7 | function sleep(t: Double) { 8 | static if defined _POSIX_SOURCE { 9 | usleep(floor(t * 1000000) as Uint); 10 | } else { 11 | if t >= 1 { 12 | sleep(t as Int); 13 | } 14 | } 15 | } 16 | 17 | /** 18 | * Returns the current time, in seconds since epoch, using gettimeofday. 19 | */ 20 | function time(): Double { 21 | var tv: timeval; 22 | gettimeofday(&tv, null); 23 | return tv.tv_sec + (tv.tv_usec / 1000000.0_f64); 24 | } 25 | -------------------------------------------------------------------------------- /std/kit/utils.kit: -------------------------------------------------------------------------------- 1 | // rules FormatString { 2 | // (fmt(${_: Byte})) => "%hh"; 3 | // (fmt(${_: Short})) => "%h"; 4 | // (fmt(${_: Int})) => "%l"; 5 | // (fmt(${_: Long})) => "%ll"; 6 | // (fmt(${_: Float})) => "%f"; 7 | // (fmt(${_: Double})) => "%f"; 8 | // } 9 | 10 | // public function println(s: CString) { 11 | // printf("%s\n", s); 12 | // } 13 | 14 | // public inline function print[S: ToString](s: S) { 15 | // println(s.toString()); 16 | // } 17 | 18 | #[noreturn] function panic(msg: Const[CString], args...) { 19 | static if defined stderr { 20 | // use stderr in environments where it's defined 21 | vfprintf(stderr, msg, (args...)); 22 | fputs("", stderr); 23 | } else { 24 | // fall back to stdout 25 | vprintf(msg, (args...)); 26 | puts(""); 27 | } 28 | abort(); 29 | } 30 | -------------------------------------------------------------------------------- /std/prelude.kit: -------------------------------------------------------------------------------- 1 | include "stdarg.h"; 2 | include "stdlib.h"; 3 | include "stdio.h"; 4 | include "stdint.h"; 5 | include "math.h" => "m"; 6 | include "string.h"; 7 | include "inttypes.h"; 8 | include "float.h"; 9 | include "limits.h"; 10 | 11 | import kit.array; 12 | import kit.cmp; 13 | import kit.common; 14 | import kit.either; 15 | import kit.iterator; 16 | import kit.list; 17 | import kit.map; 18 | import kit.math; 19 | import kit.mem; 20 | import kit.numeric; 21 | import kit.option; 22 | import kit.pointer; 23 | import kit.property; 24 | import kit.io; 25 | import kit.random; 26 | import kit.result; 27 | import kit.slice; 28 | import kit.string; 29 | import kit.utils; 30 | import kit.vector; 31 | 32 | using implicit mallocator; 33 | -------------------------------------------------------------------------------- /tests/Kit/Ast/ExprTypeSpec.hs: -------------------------------------------------------------------------------- 1 | module Kit.Ast.ExprTypeSpec where 2 | 3 | import Test.Hspec 4 | import Test.QuickCheck 5 | import Kit.Ast 6 | 7 | spec :: Spec 8 | spec = do 9 | describe "exprMapReduce" $ do 10 | it "exprMapReduce traverses the full AST, post-order" $ do 11 | let 12 | ex = 13 | e 14 | (Block 15 | [e $ Continue, e $ Break, e $ Block [e $ This, e $ Self, e $ Block [e $ This]]] 16 | ) 17 | exprMapReduce (exprDiscriminant . expr) (:) expr [] ex `shouldBe` map 18 | exprDiscriminant 19 | ([Continue, Break, This, Self, This, Block [], Block [], Block []] :: [ExprType () ()]) 20 | -------------------------------------------------------------------------------- /tests/Kit/Ast/SpanSpec.hs: -------------------------------------------------------------------------------- 1 | module Kit.Ast.SpanSpec where 2 | 3 | import Test.Hspec 4 | import Kit.Parser 5 | 6 | spec :: Spec 7 | spec = do 8 | describe "Span merging" $ do 9 | it "merges spans" $ do 10 | (sp "" 2 1 3 5) <+> (sp "" 2 1 3 5) `shouldBe` (sp "" 2 1 3 5) 11 | (sp "" 1 1 1 1) <+> (sp "" 1 2 1 3) `shouldBe` (sp "" 1 1 1 3) 12 | (sp "" 1 1 2 3) <+> (sp "" 2 1 2 4) `shouldBe` (sp "" 1 1 2 4) 13 | (sp "" 1 2 1 3) <+> (sp "" 1 1 1 1) `shouldBe` (sp "" 1 1 1 3) 14 | (sp "" 1 1 2 1) <+> (sp "" 1 3 1 4) `shouldBe` (sp "" 1 1 2 1) 15 | (sp "" 1 1 1 5) <+> (sp "" 3 1 3 5) `shouldBe` (sp "" 1 1 3 5) 16 | (sp "" 1 5 1 7) <+> (sp "" 1 2 1 3) `shouldBe` (sp "" 1 2 1 7) 17 | (sp "" 7 5 7 10) <+> (sp "" 6 1 7 6) `shouldBe` (sp "" 6 1 7 10) 18 | (NoPos) <+> (sp "" 1 2 3 4) `shouldBe` (sp "" 1 2 3 4) 19 | (sp "" 1 2 3 4) <+> (NoPos) `shouldBe` (sp "" 1 2 3 4) 20 | (NoPos) <+> (NoPos) `shouldBe` NoPos 21 | 22 | it "maintains span file info when merging" $ do 23 | (sp "abc" 2 1 3 5) <+> (sp "abc" 2 1 3 5) `shouldBe` (sp "abc" 2 1 3 5) 24 | -------------------------------------------------------------------------------- /tests/Kit/Compiler/ContextSpec.hs: -------------------------------------------------------------------------------- 1 | {-# OPTIONS_GHC -w #-} 2 | 3 | module Kit.Compiler.ContextSpec where 4 | 5 | import System.FilePath 6 | import Test.Hspec 7 | import Test.QuickCheck 8 | import Kit.Ast 9 | import Kit.Compiler 10 | import Kit.Compiler.Passes 11 | import Kit.Error 12 | import Kit.HashTable 13 | import Kit.Parser 14 | import Kit.Str 15 | 16 | newVar s = VarBinding 17 | (newVarDefinition { varName = ([], s), varType = TypeBasicType BasicTypeVoid } 18 | ) 19 | 20 | spec :: Spec 21 | spec = do 22 | describe "CompileContext" $ do 23 | it "generates code in the correct directory" $ do 24 | ctx <- newCompileContext 25 | libPath ctx ([] , "apple") `shouldBe` "build" "lib" "kit_apple.c" 26 | libPath ctx (["apple"], "banana") 27 | `shouldBe` "build" "lib" "apple" "kit_banana.c" 28 | 29 | describe "Variable resolution" $ do 30 | it "resolves variables to scopes, falling back to modules" $ do 31 | ctx <- newCompileContext 32 | m <- newMod ["abc"] "" 33 | h_insert (ctxModules ctx) (modPath m) m 34 | -- if we look for a binding in brokenMod, the test will fail 35 | let brokenMod = undefined 36 | addBinding ctx (modPath m, "a") $ newVar "a1" 37 | addBinding ctx (modPath m, "b") $ newVar "b1" 38 | addBinding ctx (modPath m, "c") $ newVar "c1" 39 | s1 <- newScope 40 | bindToScope s1 "a" $ newVar "a2" 41 | bindToScope s1 "b" $ newVar "b2" 42 | s2 <- newScope 43 | bindToScope s2 "a" $ newVar "a3" 44 | let scopes = [s2, s1] 45 | fa <- resolveVar ctx scopes brokenMod "a" 46 | fb <- resolveVar ctx scopes brokenMod "b" 47 | fc <- resolveVar ctx scopes m "c" 48 | fd <- resolveVar ctx scopes m "d" 49 | fa `shouldBe` (Just $ newVar "a3") 50 | fb `shouldBe` (Just $ newVar "b2") 51 | fc `shouldBe` (Just $ newVar "c1") 52 | fd `shouldBe` Nothing 53 | -------------------------------------------------------------------------------- /tests/Kit/Compiler/Passes/BuildModuleGraphSpec.hs: -------------------------------------------------------------------------------- 1 | module Kit.Compiler.Passes.BuildModuleGraphSpec where 2 | 3 | import Test.Hspec 4 | import Test.QuickCheck 5 | import Kit.Ast 6 | import Kit.Compiler 7 | import Kit.Compiler.Passes 8 | import Kit.Error 9 | import Kit.HashTable 10 | import Kit.Parser 11 | import Kit.Str 12 | 13 | spec :: Spec 14 | spec = do 15 | describe "tryCompile" $ do 16 | it "finds imports" $ do 17 | let exprs = 18 | case 19 | parseString "import a; import b.c; function main() {} import d;" 20 | of 21 | ParseResult e -> e 22 | Err _ -> [] 23 | m <- newMod [] "" 24 | ctx <- newCompileContext 25 | imports <- findImports ctx [] exprs 26 | map fst imports `shouldBe` [["a"], ["b", "c"], ["d"]] 27 | -------------------------------------------------------------------------------- /tests/Kit/Compiler/Passes/test_header.h: -------------------------------------------------------------------------------- 1 | // types 2 | 3 | struct Struct1 { 4 | char field1; 5 | unsigned short field2; 6 | }; 7 | 8 | typedef struct { 9 | short field1; 10 | double field2; 11 | } Struct2; 12 | 13 | typedef struct Struct3 Struct3; 14 | 15 | enum Enum1 { 16 | apple, 17 | banana, 18 | cherry 19 | }; 20 | 21 | typedef enum { 22 | kiwi, 23 | lime, 24 | mango 25 | } Enum2; 26 | 27 | // variables 28 | 29 | extern short var1; 30 | char var2 = 1; 31 | unsigned long var3; 32 | struct Struct1 struct_var1; 33 | enum Enum1 enum_var1; 34 | short *pointer_var1; 35 | short **pointer_var2; 36 | short (*pointer_var3)(short arg1); 37 | void (*func_pointer)(void); 38 | unsigned just_unsigned; 39 | const char * const_char; 40 | int * const const_ptr; 41 | 42 | // functions 43 | 44 | void void_func1(); 45 | short int_func1(); 46 | float func_with_args(short arg1, unsigned long long arg2); 47 | struct Struct1 struct_func(struct Struct2 a); 48 | float * pointer_func(int *arg1); 49 | void varargs_func(short a, ...); 50 | long void_func(void); 51 | int fake_atexit (void (*__func) (void)); 52 | extern inline void extern_inline_void_func(); 53 | static inline void static_inline_void_func(); 54 | int defined_function (int *arg, ...) {return 1;} 55 | 56 | typedef void (*fp_typedef) (void *arg1, int arg2); 57 | fp_typedef func_pointah(int arg3); 58 | -------------------------------------------------------------------------------- /tests/Kit/Compiler/ScopeSpec.hs: -------------------------------------------------------------------------------- 1 | module Kit.Compiler.ScopeSpec where 2 | 3 | import Test.Hspec 4 | import Test.QuickCheck 5 | import Kit.Compiler 6 | import Kit.Str 7 | 8 | spec :: Spec 9 | spec = do 10 | describe "Scope resolution" $ do 11 | it "resolves values from scopes" $ do 12 | scope1 <- newScope 13 | bindToScope scope1 "a" 1 14 | scope2 <- newScope 15 | bindToScope scope2 "a" 2 16 | bindToScope scope2 "b" 3 17 | scope3 <- newScope 18 | bindToScope scope3 "a" 4 19 | bindToScope scope3 "b" 5 20 | bindToScope scope3 "c" 6 21 | let scopes = [scope1, scope2, scope3] 22 | 23 | a <- resolveBinding scopes "a" 24 | b <- resolveBinding scopes "b" 25 | c <- resolveBinding scopes "c" 26 | d <- resolveBinding scopes "d" 27 | localA3 <- resolveLocal scope3 "a" 28 | a `shouldBe` Just 1 29 | b `shouldBe` Just 3 30 | c `shouldBe` Just 6 31 | d `shouldBe` Nothing 32 | localA3 `shouldBe` Just 4 33 | -------------------------------------------------------------------------------- /tests/Kit/Compiler/UnifySpec.hs: -------------------------------------------------------------------------------- 1 | module Kit.Compiler.UnifySpec where 2 | 3 | import Test.Hspec 4 | import Test.QuickCheck 5 | import Kit.Ast 6 | import Kit.Compiler 7 | import Kit.Parser 8 | import Kit.Str 9 | 10 | testUnify ctx a b c = do 11 | tctx <- newTypeContext [] 12 | mod <- newMod [] "" 13 | unification <- unify ctx tctx a b 14 | unification `shouldBe` c 15 | 16 | spec :: Spec 17 | spec = do 18 | describe "MethodTarget unification" $ do 19 | it "unifies method targets" $ do 20 | ctx <- newCompileContext 21 | let t = TypeBasicType BasicTypeCInt 22 | -- testUnify ctx t (MethodTarget t) Nothing 23 | testUnify ctx (MethodTarget t) t Nothing 24 | testUnify ctx (MethodTarget t) (MethodTarget t) (Just []) 25 | testUnify ctx 26 | (MethodTarget (TypePtr TypeVoid)) 27 | (MethodTarget (TypePtr t)) 28 | (Just []) 29 | describe "TypeSpec unification" $ do 30 | it "unifies type variables" $ do 31 | ctx <- newCompileContext 32 | a <- makeTypeVar ctx (sp "" 1 1 1 1) 33 | b <- makeTypeVar ctx (sp "" 1 1 1 1) 34 | testUnify ctx a b (Just [TypeVarIs 0 b]) 35 | testUnify ctx 36 | a 37 | (TypeInstance (["a", "b"], "mytype") []) 38 | (Just [TypeVarIs 0 (TypeInstance (["a", "b"], "mytype") [])]) 39 | testUnify ctx 40 | (TypeInstance (["a", "b"], "mytype") []) 41 | a 42 | (Just [TypeVarIs 0 (TypeInstance (["a", "b"], "mytype") [])]) 43 | -- describe "Numeric unifiation" $ do 44 | -- it "unifies numeric types" $ do 45 | -- ctx <- newCompileContext 46 | -- let t = testUnify ctx 47 | -- t (TypeInt 32) (TypeInt 64) $ Just [] 48 | -- t (TypeInt 64) (TypeInt 32) $ Just [] 49 | -- t (TypeInt 32) (TypeUint 64) $ Just [] 50 | -- t (TypeUint 32) (TypeUint 64) $ Just [] 51 | -- t (TypeUint 32) (TypeFloat 64) $ Nothing 52 | -- t (TypeInt 32) (TypeFloat 64) $ Nothing 53 | -- t (TypeFloat 32) (TypeUint 64) $ Just [] 54 | -- t (TypeFloat 32) (TypeInt 64) $ Just [] 55 | -------------------------------------------------------------------------------- /tests/Kit/Parser/StdSpec.hs: -------------------------------------------------------------------------------- 1 | module Kit.Parser.StdSpec where 2 | 3 | import Control.Monad 4 | import System.Directory 5 | import System.FilePath 6 | import Test.Hspec 7 | import Test.QuickCheck 8 | import Kit.Error 9 | import Kit.Parser 10 | import Kit.Str 11 | 12 | isKitFile :: FilePath -> Bool 13 | isKitFile f = takeExtension f == ".kit" 14 | 15 | readDir :: FilePath -> IO [FilePath] 16 | readDir d = do 17 | isDir <- doesDirectoryExist d 18 | paths <- getDirectoryContents d 19 | files <- forM (paths) $ \d2 -> do 20 | isDir <- doesDirectoryExist (d d2) 21 | if (head d2) /= '_' 22 | then if (isDir && d2 /= "." && d2 /= "..") 23 | then readDir (d d2) 24 | else return (if isKitFile d2 then [(d d2)] else []) 25 | else return [] 26 | return $ concat files 27 | 28 | stdFiles = readDir "std" 29 | 30 | {- 31 | Try parsing all files in the Kit std library and verify that they pass. 32 | 33 | TODO: also verify that they typecheck. 34 | -} 35 | spec :: Spec 36 | spec = parallel $ do 37 | describe "Kit standard library" $ do 38 | paths <- runIO stdFiles 39 | forM_ (paths) $ \path -> do 40 | it path $ do 41 | result <- parseFile path 42 | case result of 43 | ParseResult x -> True `shouldBe` True 44 | Err e -> do 45 | logError e 46 | error $ show e 47 | -------------------------------------------------------------------------------- /tests/Spec.hs: -------------------------------------------------------------------------------- 1 | {-# OPTIONS_GHC -F -pgmF hspec-discover -optF --module-name=Spec #-} 2 | -------------------------------------------------------------------------------- /tests/Test.hs: -------------------------------------------------------------------------------- 1 | module Main where 2 | 3 | import Test.Hspec.Runner 4 | import Test.Hspec.Formatters 5 | import qualified Spec 6 | 7 | main :: IO () 8 | main = hspec Spec.spec 9 | -------------------------------------------------------------------------------- /tests/functional/README.md: -------------------------------------------------------------------------------- 1 | Each Kit file in this directory will be compiled and run automatically as part of Kit.CompilerSpec. The file should contain a main function and must successfully compile. 2 | 3 | Compile any of these manually with: `kitc --run tests/functional/helloworld.kit` 4 | 5 | TODO: suffix with _fail.kit to expect failure 6 | -------------------------------------------------------------------------------- /tests/functional/abstracts.kit: -------------------------------------------------------------------------------- 1 | abstract Color: Uint32 { 2 | public static var Black: Color = 0x000000; 3 | public static var White: Color = 0xffffff; 4 | public static var Gray25: Color = 0x404040; 5 | public static var Gray50: Color = 0x808080; 6 | public static var Gray75: Color = 0xc0c0c0; 7 | public static var Red: Color = 0xff0000; 8 | public static var Green: Color = 0x00ff00; 9 | public static var Blue: Color = 0x0000ff; 10 | 11 | public function r(): Uint8 { 12 | return ((this & Color.Red) >> 16) as Uint8; 13 | } 14 | 15 | public function g(): Uint8 { 16 | return ((this & Color.Green) >> 8) as Uint8; 17 | } 18 | 19 | public function b(): Uint8 { 20 | return ((this & Color.Blue)) as Uint8; 21 | } 22 | 23 | public function getRed(): Float { 24 | return this.r() / 0xff_f32; 25 | } 26 | 27 | public function getGreen(): Float { 28 | return this.g() / 0xff_f32; 29 | } 30 | 31 | public function getBlue(): Float { 32 | return this.b() / 0xff_f32; 33 | } 34 | 35 | public function rgb(): (Uint8, Uint8, Uint8) { 36 | return (this.r(), this.g(), this.b()); 37 | } 38 | } 39 | 40 | abstract ColorWithAlpha: Color { 41 | public function a(): Uint8 { 42 | return ((this & 0xff000000) >> 24) as Uint8; 43 | } 44 | 45 | public function getAlpha(): Float { 46 | return this.a() / 0xff_f32; 47 | } 48 | } 49 | 50 | abstract AbstractNamespace: Void { 51 | public static var constString = "hello from a namespaced static var"; 52 | } 53 | 54 | function main() { 55 | var myColor: Color = 0x123456; 56 | printf("%u\n", myColor.r()); 57 | printf("%u\n", myColor.g()); 58 | printf("%u\n", myColor.b()); 59 | printf("%.2f\n", myColor.getRed()); 60 | printf("%.2f\n", Color.Gray25.getGreen()); 61 | printf("%.2f\n", Color.Gray50.getBlue()); 62 | printf("%.2f\n", Color.Gray75.getRed()); 63 | var rgb = myColor.rgb(); 64 | 65 | var c: ColorWithAlpha = 0xff000000 | Color.Gray50; 66 | printf("%.2f\n", c.getBlue()); 67 | printf("%.2f\n", c.getAlpha()); 68 | 69 | printf("%s\n", AbstractNamespace.constString); 70 | } 71 | -------------------------------------------------------------------------------- /tests/functional/abstracts.stdout: -------------------------------------------------------------------------------- 1 | 18 2 | 52 3 | 86 4 | 0.07 5 | 0.25 6 | 0.50 7 | 0.75 8 | 0.50 9 | 1.00 10 | hello from a namespaced static var 11 | -------------------------------------------------------------------------------- /tests/functional/allocation.kit: -------------------------------------------------------------------------------- 1 | include "stdlib.h"; 2 | 3 | function specialAlloc(size: Size): Ptr[Void] { 4 | printf("special_alloc %zu\n", size); 5 | return malloc(size); 6 | } 7 | 8 | struct MyStruct { 9 | var a: Int; 10 | var b: Float; 11 | 12 | public static function new(allocator: Box[Allocator]): Ptr[MyStruct] { 13 | return allocator.alloc(sizeof MyStruct); 14 | } 15 | } 16 | 17 | function main() { 18 | var callocator: Box[Allocator] = struct SimpleAllocator { 19 | alloc: specialAlloc, 20 | calloc: callocWrapper, 21 | free: free, 22 | }; 23 | 24 | // use the implicit `mallocator` 25 | var s1 = MyStruct.new(); 26 | s1.b = 2.5; 27 | printf("%.1f\n", s1.b); 28 | 29 | var s2: Ptr[MyStruct]; 30 | using implicit callocator { 31 | s2 = MyStruct.new(); 32 | } 33 | s2.b = 4.1; 34 | printf("%.1f\n", s2.b); 35 | } 36 | -------------------------------------------------------------------------------- /tests/functional/allocation.stdout: -------------------------------------------------------------------------------- 1 | 2.5 2 | special_alloc 8 3 | 4.1 4 | -------------------------------------------------------------------------------- /tests/functional/associated_types.kit: -------------------------------------------------------------------------------- 1 | trait IdTrait(AssocT) { 2 | public function id(): AssocT; 3 | } 4 | 5 | implement IdTrait(Int) for Int { 6 | public function id() { 7 | return this; 8 | } 9 | } 10 | 11 | implement IdTrait(Int) for Float { 12 | public function id() { 13 | return this as Int; 14 | } 15 | } 16 | 17 | implement IdTrait(CString) for CString { 18 | public function id() { 19 | return this; 20 | } 21 | } 22 | 23 | trait ConsTrait[T](AssocT) { 24 | public function cons(v1: T, v2: AssocT); 25 | } 26 | 27 | implement ConsTrait[Int](Float) for Int { 28 | public function cons(v1: Int, v2: Float) { 29 | printf("%i %i %.1f\n", this, v1, v2); 30 | } 31 | } 32 | 33 | function main() { 34 | var a = 1_i as Box[IdTrait]; 35 | var b: Box[IdTrait] = 2_f32; 36 | var c: Box[IdTrait] = "hello"; 37 | 38 | printf("%i\n", a.id()); 39 | printf("%i\n", b.id()); 40 | printf("%s\n", c.id()); 41 | 42 | var i: Int = 1; 43 | var x: Box[ConsTrait[Int]] = i; 44 | x.cons(2_i, 3_f32); 45 | } 46 | -------------------------------------------------------------------------------- /tests/functional/associated_types.stdout: -------------------------------------------------------------------------------- 1 | 1 2 | 2 3 | hello 4 | 1 2 3.0 5 | -------------------------------------------------------------------------------- /tests/functional/autorefderef.kit: -------------------------------------------------------------------------------- 1 | struct MyStruct { 2 | var a: Int; 3 | var b: Int; 4 | var c: Ptr[Int]; 5 | } 6 | 7 | function f1(x: MyStruct) { 8 | printf("%i\n", x.a); 9 | } 10 | 11 | function f2(x: Ptr[MyStruct]) { 12 | printf("%i\n", x.b); 13 | } 14 | 15 | function f3(x: Ptr[Ptr[MyStruct]]) { 16 | printf("%i\n", *(x.c)); 17 | } 18 | 19 | function main() { 20 | var myInt: Int = 3; 21 | var myVal = struct MyStruct { 22 | a: 1, 23 | b: 2, 24 | // auto-reference 25 | c: myInt, 26 | }; 27 | 28 | // field access on pointers 29 | var p1: Ptr[MyStruct] = &myVal; 30 | printf("%i\n", p1.a); 31 | var p2: Ptr[Ptr[MyStruct]] = &p1; 32 | printf("%i\n", p2.b); 33 | var p3: MyStruct = p1; 34 | printf("%i\n", *(p3.c)); 35 | // let's get crazy 36 | var ptr1 = &myVal; 37 | var ptr2 = &ptr1; 38 | var ptr3 = &ptr2; 39 | var ptr4 = &ptr3; 40 | var ptr5 = &ptr4; 41 | var p4: MyStruct = ptr5; 42 | printf("%i\n", *(p4.c)); 43 | 44 | f1(myVal); 45 | f1(p1); 46 | f1(p2); 47 | f1(p3); 48 | f1(p4); 49 | f2(myVal); 50 | f2(p1); 51 | f2(p2); 52 | f2(p3); 53 | f2(p4); 54 | f3(p1); 55 | f3(p2); 56 | f3(*ptr5); 57 | f3(* (*ptr5)); 58 | 59 | var localString = "a string"; 60 | var localStringPtr: Ptr[CString] = localString; 61 | var localCharPtrPtr: Ptr[Ptr[Char]] = localString; 62 | printf("%s\n", *localStringPtr); 63 | printf("%s\n", *localCharPtrPtr); 64 | } 65 | -------------------------------------------------------------------------------- /tests/functional/autorefderef.stdout: -------------------------------------------------------------------------------- 1 | 1 2 | 2 3 | 3 4 | 3 5 | 1 6 | 1 7 | 1 8 | 1 9 | 1 10 | 2 11 | 2 12 | 2 13 | 2 14 | 2 15 | 3 16 | 3 17 | 3 18 | 3 19 | a string 20 | a string 21 | -------------------------------------------------------------------------------- /tests/functional/box.kit: -------------------------------------------------------------------------------- 1 | include "inttypes.h"; 2 | 3 | struct MyStruct { 4 | public var a: Int; 5 | public var b: Float; 6 | } 7 | 8 | trait Greeter { 9 | public function greet(): Void; 10 | public function original(): Ptr[Void] { 11 | return &this; 12 | } 13 | } 14 | 15 | implement Greeter for Int { 16 | public function greet() { 17 | printf("Hello from Int %i\n", this); 18 | } 19 | } 20 | 21 | implement Greeter for Int64 { 22 | public function greet() { 23 | printf(```"Hellooo from Int64 %" PRId64 "\n"```: CString, this); 24 | } 25 | } 26 | 27 | implement Greeter for Float32 { 28 | public function greet() { 29 | printf("Howdy from Float %.2f\n", this); 30 | } 31 | } 32 | 33 | implement Greeter for MyStruct { 34 | public function greet() { 35 | printf("Hey from MyStruct\n"); 36 | greet(this.a); 37 | greet(this.b); 38 | } 39 | } 40 | 41 | implement Greeter for Bool { 42 | public function greet() { 43 | if this { 44 | printf("yep\n"); 45 | } else { 46 | printf("nope\n"); 47 | } 48 | } 49 | } 50 | 51 | implement Greeter for (Int, Int) { 52 | public function greet() { 53 | printf("hello from two ints: (%i, %i)\n", this[0], this[1]); 54 | } 55 | } 56 | 57 | function greet(x: Box[Greeter]) { 58 | x.greet(); 59 | } 60 | 61 | function main() { 62 | var a: Int = 1; 63 | var x: Box[Greeter] = a; 64 | greet(x); 65 | 66 | var a1 = (x as Ptr[Void]) as Ptr[Int]; 67 | printf("%i\n", *a1); 68 | 69 | var b = 7_i; 70 | greet(b); 71 | greet(5_f32); 72 | greet(10000000000000_i64); 73 | 74 | greet(struct MyStruct {a: 100, b: 3.14}); 75 | 76 | greet(true); 77 | greet(false); 78 | 79 | greet((3_i, 5_i)); 80 | 81 | var original = x.original() as Ptr[Int]; 82 | printf("%i\n", *original); 83 | } 84 | -------------------------------------------------------------------------------- /tests/functional/box.stdout: -------------------------------------------------------------------------------- 1 | Hello from Int 1 2 | 1 3 | Hello from Int 7 4 | Howdy from Float 5.00 5 | Hellooo from Int64 10000000000000 6 | Hey from MyStruct 7 | Hello from Int 100 8 | Howdy from Float 3.14 9 | yep 10 | nope 11 | hello from two ints: (3, 5) 12 | 1 13 | -------------------------------------------------------------------------------- /tests/functional/c_macro_expansion.kit: -------------------------------------------------------------------------------- 1 | function main() { 2 | printf("%i\n", CHAR_BIT: Int); 3 | } 4 | -------------------------------------------------------------------------------- /tests/functional/c_macro_expansion.stdout: -------------------------------------------------------------------------------- 1 | 8 2 | -------------------------------------------------------------------------------- /tests/functional/carray.kit: -------------------------------------------------------------------------------- 1 | struct A { 2 | var a: Int; 3 | } 4 | 5 | struct B { 6 | var b: Int; 7 | var a: CArray[A]; 8 | } 9 | 10 | var topLevelArray: CArray[A, 2] = [struct A {a: 1}, struct A {a: 2}]; 11 | 12 | function main() { 13 | var a: CArray[Int, 3] = empty; 14 | printf("%i\n", a[0]); 15 | printf("%i\n", a[1]); 16 | printf("%i\n", a[2]); 17 | 18 | var b: CArray[Int, 4]; 19 | b = [4, 5, 6, 7]; 20 | printf("%i\n", b[1]); 21 | printf("%i\n", b.length); 22 | 23 | var c: CArray[Int, 5] = [8, 9, 10, 11, 12]; 24 | printf("%i\n", c[2]); 25 | printf("%i\n", c.length); 26 | 27 | printf("%i\n", ([1, 2, 3, 4, 5, 6]).length); 28 | 29 | var arrayPtr: Ptr[Int] = c; 30 | printf("%i\n", *arrayPtr); 31 | printf("%i\n", *(arrayPtr + 1)); 32 | printf("%i\n", *(arrayPtr + 2)); 33 | 34 | for i in c { 35 | printf("i: %i\n", i); 36 | } 37 | 38 | printf("0.a=%i 1.a=%i\n", topLevelArray[0].a, topLevelArray[1].a); 39 | } 40 | -------------------------------------------------------------------------------- /tests/functional/carray.stdout: -------------------------------------------------------------------------------- 1 | 0 2 | 0 3 | 0 4 | 5 5 | 4 6 | 10 7 | 5 8 | 6 9 | 8 10 | 9 11 | 10 12 | i: 8 13 | i: 9 14 | i: 10 15 | i: 11 16 | i: 12 17 | 0.a=1 1.a=2 18 | -------------------------------------------------------------------------------- /tests/functional/casting.kit: -------------------------------------------------------------------------------- 1 | struct MyStruct { 2 | var a: Int = 0; 3 | } 4 | 5 | function main() { 6 | var a: Int = 1; 7 | var b: Float = 2.5; 8 | 9 | printf("%i\n", b as Int); 10 | printf("%.1f\n", a as Float); 11 | 12 | var x = malloc(4) as Ptr[MyStruct]; 13 | x.a = 5; 14 | printf("%i\n", x.a); 15 | } 16 | -------------------------------------------------------------------------------- /tests/functional/casting.stdout: -------------------------------------------------------------------------------- 1 | 2 2 | 1.0 3 | 5 4 | -------------------------------------------------------------------------------- /tests/functional/const.kit: -------------------------------------------------------------------------------- 1 | struct MyStruct { 2 | public static const MY_CONST: Int = 5; 3 | 4 | var a: Int = 1; 5 | const b: Int = 2; 6 | } 7 | 8 | function f(x: Const[Ptr[Char]]) { 9 | printf("%s\n", x); 10 | } 11 | 12 | function main() { 13 | const a: Int = 1; 14 | printf("%i\n", a); 15 | 16 | const x = struct MyStruct { 17 | a: 1, 18 | b: 2, 19 | }; 20 | printf("%i\n", x.b); 21 | 22 | printf("%i\n", MyStruct.MY_CONST); 23 | 24 | var c: CString = "abc"; 25 | var d: Const[CString] = c; 26 | var e: Const[Ptr[Char]] = c; 27 | 28 | f(e); 29 | } 30 | -------------------------------------------------------------------------------- /tests/functional/const.stdout: -------------------------------------------------------------------------------- 1 | 1 2 | 2 3 | 5 4 | abc 5 | -------------------------------------------------------------------------------- /tests/functional/const_type.kit: -------------------------------------------------------------------------------- 1 | struct ByteBuffer[$N] { 2 | var data: CArray[Uint8, N] = empty; 3 | 4 | rules { 5 | // BUG: type rules need to resolve type params in the context of their definer 6 | ($this[$i]) => if $i < 0 then $this.data[N - $i] else $this.data[$i]; 7 | } 8 | 9 | public static function new(): ByteBuffer[N] { 10 | return struct Self { 11 | data: empty, 12 | }; 13 | } 14 | 15 | public static function new2(): ByteBuffer[N] { 16 | var s = struct Self {}; 17 | s.data[0] = 1; 18 | return s; 19 | } 20 | 21 | public function capacity(): Size { 22 | return N; 23 | } 24 | 25 | public function eq(other: Self): Bool { 26 | for i in 0 ... N { 27 | if this.data[i] != other.data[i] { 28 | return false; 29 | } 30 | } 31 | return true; 32 | } 33 | } 34 | 35 | function main() { 36 | var x: ByteBuffer[2] = struct ByteBuffer[2] {data: empty}; 37 | x.data = [1, 2]; 38 | printf("%zu\n", x.capacity()); 39 | 40 | var y: ByteBuffer[0x2] = ByteBuffer.new(); 41 | var z: ByteBuffer[0b10] = ByteBuffer.new2(); 42 | printf("%s\n", if y.eq(z) then "equal" else "not equal"); 43 | 44 | // BUG: having two monomorphs breaks the type interface! 45 | var a: ByteBuffer[0x100] = ByteBuffer[0x100].new(); 46 | // not yet implemented 47 | // var b: ByteBuffer[128 + 128] = a; 48 | printf("%zu\n", a.capacity()); 49 | // printf("%zu\n", b.capacity()); 50 | a.data[0] = 1; 51 | 52 | // a[2] = 0xfe; 53 | // a[0xff] = 0xed; 54 | // printf("%.2x\n", a[2]); 55 | // printf("%.2x\n", a[-1]); 56 | } 57 | -------------------------------------------------------------------------------- /tests/functional/const_type.stdout: -------------------------------------------------------------------------------- 1 | 2 2 | not equal 3 | 256 4 | -------------------------------------------------------------------------------- /tests/functional/cstring.kit: -------------------------------------------------------------------------------- 1 | function main() { 2 | for i in "hello, world!" { 3 | printf("%c", i); 4 | } 5 | puts(""); 6 | 7 | puts(if "abcdefg".startsWith("abc") then "abcdefg starts with abc" else "wrong"); 8 | puts(if "abcdefg".startsWith("efg") then "wrong" else "abcdefg does not start with efg"); 9 | puts(if "abcdefg".startsWith("") then "abcdefg starts with empty string" else "wrong"); 10 | puts(if "abcdefg".startsWith("abcdefg") then "abcdefg starts with abcdefg" else "wrong"); 11 | 12 | puts(if "abcdefg".endsWith("efg") then "abcdefg ends with efg" else "wrong"); 13 | puts(if "abcdefg".endsWith("def") then "wrong" else "abcdefg does not end with def"); 14 | puts(if "abcdefg".endsWith("") then "abcdefg ends with empty string" else "wrong"); 15 | } 16 | -------------------------------------------------------------------------------- /tests/functional/cstring.stdout: -------------------------------------------------------------------------------- 1 | hello, world! 2 | abcdefg starts with abc 3 | abcdefg does not start with efg 4 | abcdefg starts with empty string 5 | abcdefg starts with abcdefg 6 | abcdefg ends with efg 7 | abcdefg does not end with def 8 | abcdefg ends with empty string 9 | -------------------------------------------------------------------------------- /tests/functional/defined.kit: -------------------------------------------------------------------------------- 1 | function main() { 2 | var b = defined printf; 3 | puts(if b then "true" else "false"); 4 | 5 | static if defined printf { 6 | puts("printf exists"); 7 | } else { 8 | puts("printf doesn't exist"); 9 | } 10 | static if defined printf123987 { 11 | puts("printf123987 exists"); 12 | } else { 13 | puts("printf123987 doesn't exist"); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /tests/functional/defined.stdout: -------------------------------------------------------------------------------- 1 | true 2 | printf exists 3 | printf123987 doesn't exist 4 | -------------------------------------------------------------------------------- /tests/functional/double_wildcard.kit: -------------------------------------------------------------------------------- 1 | import test1.**; 2 | 3 | function main() { 4 | f(); 5 | g(); 6 | } 7 | -------------------------------------------------------------------------------- /tests/functional/double_wildcard.stdout: -------------------------------------------------------------------------------- 1 | hello world! 2 | -------------------------------------------------------------------------------- /tests/functional/empty.kit: -------------------------------------------------------------------------------- 1 | function main() {} 2 | -------------------------------------------------------------------------------- /tests/functional/enums.kit: -------------------------------------------------------------------------------- 1 | include "test_header1.h"; 2 | 3 | // we should be mangling the discriminant, and name collision within the same 4 | // module should be allowed, with the last declaration winning; if either of 5 | // these fail, the module won't compile 6 | enum MyRedundantEnum { 7 | Apple; 8 | Banana; 9 | Strawberry; 10 | } 11 | 12 | enum MySimpleEnum { 13 | Apple; 14 | Banana; 15 | Strawberry; 16 | 17 | public function print(): Void { 18 | match this { 19 | Apple => printf("%s\n", "apple"); 20 | Banana => printf("%s\n", "banana"); 21 | Strawberry => printf("%s\n", "strawberry"); 22 | } 23 | } 24 | } 25 | 26 | enum MyComplexEnum { 27 | Apple2(i: Int); 28 | Banana2(a: Float, b: CString = "abc"); 29 | Strawberry2; 30 | 31 | public function print(): Void { 32 | match this { 33 | Apple2(i) => { 34 | printf("Apple2: %i\n", i); 35 | } 36 | Banana2(a, b) => { 37 | printf("Banana2: %.1f, %s\n", a, b); 38 | } 39 | Strawberry2 => { 40 | printf("Strawberry2\n"); 41 | } 42 | } 43 | } 44 | } 45 | 46 | function main() { 47 | // simple enums 48 | var a = Apple; 49 | var b = Banana; 50 | 51 | // complex enums with fields 52 | var c = Apple2(1); 53 | var d = Banana2(5, "hello"); 54 | var e = Strawberry2; 55 | puts(d.Banana2.b); 56 | 57 | // unification between enum type and variants 58 | var f: MyComplexEnum = d; 59 | f = e; 60 | 61 | // simple enum equality 62 | if (a != b) { 63 | printf("hello!\n"); 64 | } 65 | 66 | // TODO: complex enum equality (not yet implemented) 67 | 68 | // simple enum methods + match 69 | a.print(); 70 | b.print(); 71 | 72 | // complex enum match with destructuring 73 | c.print(); 74 | d.print(); 75 | e.print(); 76 | 77 | var g = MyRedundantEnum.Apple; 78 | 79 | puts("MySimpleEnum variants:"); 80 | for variant in MySimpleEnum.variants { 81 | printf("- %i: ", variant as Int); 82 | variant.print(); 83 | } 84 | 85 | var x: TestEnum = Var2; 86 | var y: Int = x; 87 | printf("%i\n", y); 88 | 89 | match Banana2(1) { 90 | Banana2(_, s) => puts(s); 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /tests/functional/enums.stdout: -------------------------------------------------------------------------------- 1 | hello 2 | hello! 3 | apple 4 | banana 5 | Apple2: 1 6 | Banana2: 5.0, hello 7 | Strawberry2 8 | MySimpleEnum variants: 9 | - 0: apple 10 | - 1: banana 11 | - 2: strawberry 12 | 1 13 | abc 14 | -------------------------------------------------------------------------------- /tests/functional/extend.kit: -------------------------------------------------------------------------------- 1 | struct A { 2 | public var a: Int; 3 | public var b: Int; 4 | 5 | public static function f1() { 6 | puts("f1"); 7 | } 8 | } 9 | 10 | extend A { 11 | public var c: Int; 12 | 13 | public static function f2() { 14 | puts("f2"); 15 | } 16 | } 17 | 18 | struct StartsEmpty {} 19 | extend StartsEmpty { 20 | public var nowItHasAField: Int; 21 | } 22 | 23 | function main() { 24 | var s = struct A {a: 1, b: 1, c: 1}; 25 | printf("%i %i %i\n", s.a, s.b, s.c); 26 | A.f1(); 27 | A.f2(); 28 | } 29 | -------------------------------------------------------------------------------- /tests/functional/extend.stdout: -------------------------------------------------------------------------------- 1 | 1 1 1 2 | f1 3 | f2 4 | -------------------------------------------------------------------------------- /tests/functional/extern.kit: -------------------------------------------------------------------------------- 1 | #[extern] function externFunc() { 2 | printf("extern func\n"); 3 | } 4 | 5 | function main() { 6 | externFunc(); 7 | } 8 | -------------------------------------------------------------------------------- /tests/functional/for.kit: -------------------------------------------------------------------------------- 1 | function main() { 2 | for i in 1 ... 6 { 3 | printf("%i\n", i); 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /tests/functional/for.stdout: -------------------------------------------------------------------------------- 1 | 1 2 | 2 3 | 3 4 | 4 5 | 5 6 | -------------------------------------------------------------------------------- /tests/functional/functions.kit: -------------------------------------------------------------------------------- 1 | /** 2 | * Trivial function, casts an Int to a Float. 3 | */ 4 | function f(i: Int): Float { 5 | return i; 6 | } 7 | 8 | /** 9 | * Takes f + its arg and applies. 10 | */ 11 | function g(func: function (Int) -> Float, i: Int): Float { 12 | f(1); 13 | return func(i); 14 | } 15 | 16 | /** 17 | * Varargs test. 18 | */ 19 | function k(func: function (CString, args...) -> Void, s: CString) { 20 | func(s, 1, 2, 3); 21 | } 22 | 23 | function l(s: CString, args...) { 24 | printf("hello, %s\n", s); 25 | } 26 | 27 | function withArgDefaults(i: Int, j: Float = 2): Float { 28 | return j; 29 | } 30 | 31 | struct MyStruct { 32 | var a: Int; 33 | 34 | /** 35 | * Nested function types on a static method. Calls g, which calls f. 36 | */ 37 | public static function h(func: function (function (Int) -> Float, Int) -> Float, func2: function (Int) -> Float, i: Int): Float { 38 | return func(func2, i); 39 | } 40 | 41 | /** 42 | * Same as above but inferring the function types. 43 | */ 44 | public static function j(func, func2, i: Int): Float { 45 | return func(func2, i); 46 | } 47 | } 48 | 49 | function main() { 50 | printf("%.1f\n", MyStruct.h(g, f, 4)); 51 | printf("%.1f\n", MyStruct.j(g, f, 6)); 52 | k(l, "world"); 53 | printf("%.1f\n", withArgDefaults(1)); 54 | printf("%.1f\n", withArgDefaults(1, 3.0)); 55 | } 56 | -------------------------------------------------------------------------------- /tests/functional/functions.stdout: -------------------------------------------------------------------------------- 1 | 4.0 2 | 6.0 3 | hello, world 4 | 2.0 5 | 3.0 6 | -------------------------------------------------------------------------------- /tests/functional/generic_functions.kit: -------------------------------------------------------------------------------- 1 | function genericFunction[T](fmt: CString, v: T) { 2 | printf(fmt, v); 3 | } 4 | 5 | function genericFunction2[T, U](fmt: CString, t: T, u: U) { 6 | printf(fmt, t, u); 7 | } 8 | 9 | function main() { 10 | genericFunction("%i\n", 1); 11 | genericFunction("%i\n", 2); 12 | genericFunction("%.2f\n", 3.0); 13 | genericFunction("%s\n", "hello"); 14 | 15 | genericFunction2("%s%i\n", "hello", 1); 16 | genericFunction2("%i%s\n", 1, "hello"); 17 | } 18 | -------------------------------------------------------------------------------- /tests/functional/generic_functions.stdout: -------------------------------------------------------------------------------- 1 | 1 2 | 2 3 | 3.00 4 | hello 5 | hello1 6 | 1hello 7 | -------------------------------------------------------------------------------- /tests/functional/generic_traits.kit: -------------------------------------------------------------------------------- 1 | trait GenericPrinter[T] { 2 | public function print(value: T): Void; 3 | } 4 | 5 | implement GenericPrinter[Int] for Int { 6 | public function print(value: Int) { 7 | printf("%i %i\n", this, value); 8 | } 9 | } 10 | 11 | implement GenericPrinter[Float] for Int { 12 | public function print(value: Float) { 13 | printf("%.2f %.2f\n", this as Float, value); 14 | } 15 | } 16 | 17 | implement GenericPrinter[CString] for CString { 18 | public function print(value: CString) { 19 | printf("%s %s\n", this, value); 20 | } 21 | } 22 | 23 | function main() { 24 | var a: Int = 1; 25 | var aBox: Box[GenericPrinter[Int]] = a; 26 | aBox.print(2); 27 | 28 | var b: Int = 1; 29 | var bBox: Box[GenericPrinter[Float]] = b; 30 | bBox.print(3); 31 | 32 | var c = "hello"; 33 | var cBox: Box[GenericPrinter[CString]] = c; 34 | cBox.print("world"); 35 | 36 | var d = "hi"; 37 | var dBox: Box[GenericPrinter[CString]] = d; 38 | dBox.print("there"); 39 | } 40 | -------------------------------------------------------------------------------- /tests/functional/generic_traits.stdout: -------------------------------------------------------------------------------- 1 | 1 2 2 | 1.00 3.00 3 | hello world 4 | hi there 5 | -------------------------------------------------------------------------------- /tests/functional/generic_types.stdout: -------------------------------------------------------------------------------- 1 | 1 2 | 0 3 | 1 4 | 2 5 | hello 6 | greeting: 1 7 | greeting: hello 8 | greetings from 1 and 5 9 | 10 10 | 20.50 11 | 40 12 | 77.77 13 | one: 1 14 | two: 2.0, 3.0 15 | one: 4 16 | two: 5.0, 6.0 17 | Hello 1 18 | Hello hello 19 | -------------------------------------------------------------------------------- /tests/functional/helloworld.kit: -------------------------------------------------------------------------------- 1 | function main() { 2 | printf("%s\n", "hello world!"); 3 | } 4 | -------------------------------------------------------------------------------- /tests/functional/helloworld.stdout: -------------------------------------------------------------------------------- 1 | hello world! 2 | -------------------------------------------------------------------------------- /tests/functional/identifiers.kit: -------------------------------------------------------------------------------- 1 | function panic(i: Int) { 2 | // this should shadow the builtin panic function 3 | printf("called local panic\n"); 4 | } 5 | 6 | function main() { 7 | panic(1); 8 | 9 | // the function signature differs, so this will fail to compile unless 10 | // it resolve to the real builtin panic function 11 | var x: function (Const[CString], args...) -> Void = kit.utils.panic; 12 | 13 | var l1: List[Int] = kit.list.List.Empty; 14 | var l2: kit.list.List[Int] = kit.list.List[Int].Empty; 15 | // var l3 = kit.list.List.Empty; 16 | } 17 | -------------------------------------------------------------------------------- /tests/functional/identifiers.stdout: -------------------------------------------------------------------------------- 1 | called local panic 2 | -------------------------------------------------------------------------------- /tests/functional/implicits.kit: -------------------------------------------------------------------------------- 1 | abstract SpecialInt: Int; 2 | abstract SpecialFloat: Float; 3 | 4 | function f(a: SpecialInt, b: SpecialFloat, c: CString) { 5 | printf("hello %i %.1f %s!\n", a, b, c); 6 | } 7 | 8 | function main() { 9 | // numeric types aren't a great example of implicits; for the test to pass, 10 | // using abstracts so they don't unify with each other 11 | var a: SpecialInt = 1; 12 | var b: SpecialFloat = 2.0; 13 | var c: CString = "world2"; 14 | 15 | using implicit a { 16 | f(3.5, "world"); 17 | } 18 | 19 | // implicit order shouldn't matter 20 | using implicit b, implicit a { 21 | f("world"); 22 | 23 | // nested implicit 24 | using implicit c f(); 25 | } 26 | 27 | var d: Float = 2.5; 28 | var e: Float; 29 | using implicit d { 30 | e = 4 + (implicit Float); 31 | } 32 | printf("%.1f\n", e); 33 | 34 | // if we cast e to an Int and promote to SpecialInt, this works 35 | using implicit ((e as Int) as SpecialInt) { 36 | f(5.1, "world"); 37 | } 38 | 39 | // this does not use the implicit 40 | using implicit (e as Int) { 41 | f(a, 5.2, "world"); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /tests/functional/implicits.stdout: -------------------------------------------------------------------------------- 1 | hello 1 3.5 world! 2 | hello 1 2.0 world! 3 | hello 1 2.0 world2! 4 | 6.5 5 | hello 6 5.1 world! 6 | hello 1 5.2 world! 7 | -------------------------------------------------------------------------------- /tests/functional/inline_c.kit: -------------------------------------------------------------------------------- 1 | include "inttypes.h"; 2 | 3 | function main() { 4 | var x: Int = 1; 5 | ```x += 2```: Void; 6 | printf("%i\n", x); 7 | 8 | var y: Int16 = 5; 9 | printf(```"%" PRId16 "\n"```: CString, y); 10 | } 11 | -------------------------------------------------------------------------------- /tests/functional/inline_c.stdout: -------------------------------------------------------------------------------- 1 | 3 2 | 5 3 | -------------------------------------------------------------------------------- /tests/functional/issues/issue105.kit: -------------------------------------------------------------------------------- 1 | struct MyStruct { 2 | public var x: Int; 3 | public var y: Float; 4 | } 5 | 6 | function main() { 7 | var a = Some(struct MyStruct {x: 1, y: 2}); 8 | match a { 9 | Some(x) => match if x.x == 1 then true else false { 10 | true => puts("1"); 11 | default => puts("something else"); 12 | } 13 | } 14 | 15 | if (if (a = None).isNone() then true else false) { 16 | puts("None"); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /tests/functional/issues/issue105.stdout: -------------------------------------------------------------------------------- 1 | 1 2 | None 3 | -------------------------------------------------------------------------------- /tests/functional/issues/issue106.kit: -------------------------------------------------------------------------------- 1 | struct MyStruct { 2 | var a: Int; 3 | } 4 | 5 | function f(x: Option[MyStruct] = None) { 6 | return x; 7 | } 8 | 9 | function g(x: Option[MyStruct] = Option[MyStruct].None) { 10 | return x; 11 | } 12 | 13 | function main() { 14 | var s = f(); 15 | if s.isNone() { 16 | puts("hi1"); 17 | } 18 | 19 | var t = g(); 20 | if t.isNone() { 21 | puts("hi2"); 22 | } 23 | 24 | var u = f(Some(struct MyStruct)); 25 | if u.isNone() { 26 | puts("hi3"); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /tests/functional/issues/issue106.stdout: -------------------------------------------------------------------------------- 1 | hi1 2 | hi2 3 | -------------------------------------------------------------------------------- /tests/functional/issues/issue111.kit: -------------------------------------------------------------------------------- 1 | include "test_header1.h"; 2 | 3 | #[extern] function myUnimplementedFunction() { 4 | puts("it works!"); 5 | } 6 | 7 | function main() { 8 | myUnimplementedFunction(); 9 | } 10 | -------------------------------------------------------------------------------- /tests/functional/issues/issue111.stdout: -------------------------------------------------------------------------------- 1 | it works! 2 | -------------------------------------------------------------------------------- /tests/functional/issues/issue124.kit: -------------------------------------------------------------------------------- 1 | #[promote] abstract MyType: CArray[Int, 4] { 2 | rules { 3 | ($this[$a] = $b) => printf("set: %s = %s\n", $a, $b); 4 | ($this[$a]) => printf("get: %s\n", $a); 5 | 6 | ($this.abc = $x) => printf("field write: %s\n", $x); 7 | ($this.abc) => printf("field read\n"); 8 | } 9 | } 10 | 11 | function main() { 12 | var a: MyType = [1, 2, 3, 4]; 13 | a["test1"] = "test2"; 14 | a["test3"]; 15 | 16 | a.abc = "test4"; 17 | a.abc; 18 | } 19 | -------------------------------------------------------------------------------- /tests/functional/issues/issue124.stdout: -------------------------------------------------------------------------------- 1 | set: test1 = test2 2 | get: test3 3 | field write: test4 4 | field read 5 | -------------------------------------------------------------------------------- /tests/functional/issues/issue132.kit: -------------------------------------------------------------------------------- 1 | struct MyVal { 2 | var val: Int; 3 | 4 | rules { 5 | ($this = ${other: Int}) => $this.val = $other; 6 | } 7 | } 8 | 9 | 10 | function main() { 11 | var s = struct MyVal {val: 0}; 12 | s = 1_i; 13 | printf("%i\n", s.val); 14 | } 15 | -------------------------------------------------------------------------------- /tests/functional/issues/issue137.kit: -------------------------------------------------------------------------------- 1 | macro boldify(s: CString) { 2 | printf('"** %s **"', s); 3 | } 4 | 5 | function main() { 6 | puts(boldify("HELLO!")); 7 | puts(boldify("THERE!")); 8 | puts(issue137.boldify("WORLD!")); 9 | } 10 | -------------------------------------------------------------------------------- /tests/functional/issues/issue137.stdout: -------------------------------------------------------------------------------- 1 | ** HELLO! ** 2 | ** THERE! ** 3 | ** WORLD! ** 4 | -------------------------------------------------------------------------------- /tests/functional/issues/issue14.kit: -------------------------------------------------------------------------------- 1 | function main() { 2 | var x: CArray[Int, 4] = [1, 2, 3, 4]; 3 | printf("%i %i %i %i\n", x[0], x[1], x[2], x[3]); 4 | x = empty; 5 | printf("%i %i %i %i\n", x[0], x[1], x[2], x[3]); 6 | } 7 | -------------------------------------------------------------------------------- /tests/functional/issues/issue14.stdout: -------------------------------------------------------------------------------- 1 | 1 2 3 4 2 | 0 0 0 0 3 | -------------------------------------------------------------------------------- /tests/functional/issues/issue16.kit: -------------------------------------------------------------------------------- 1 | function exitFunc() { 2 | printf("exiting!\n"); 3 | } 4 | 5 | function main() { 6 | atexit(exitFunc); 7 | } 8 | -------------------------------------------------------------------------------- /tests/functional/issues/issue16.stdout: -------------------------------------------------------------------------------- 1 | exiting! 2 | -------------------------------------------------------------------------------- /tests/functional/issues/issue22.kit: -------------------------------------------------------------------------------- 1 | rules MacroRules { 2 | (MACRO_LIKE_FUNC(${i: Int})) => printf("macro-like func: %i\n", $i); 3 | } 4 | 5 | function main() using rules MacroRules { 6 | MACRO_LIKE_FUNC(123_i); 7 | } 8 | -------------------------------------------------------------------------------- /tests/functional/issues/issue22.stdout: -------------------------------------------------------------------------------- 1 | macro-like func: 123 2 | -------------------------------------------------------------------------------- /tests/functional/issues/issue34.kit: -------------------------------------------------------------------------------- 1 | struct Vector3[T: Numeric] { 2 | public var x: T; 3 | public var y: T; 4 | public var z: T; 5 | public static const Zero = struct Self {x: 0, y: 0, z: 0}; 6 | } 7 | 8 | function main() { 9 | var vecf: Vector3[Float] = Vector3[Float].Zero; 10 | var vecd: Vector3[Double] = Vector3[Double].Zero; 11 | var veci: Vector3[Int] = Vector3[Int].Zero; 12 | var v = Vector3[Int].Zero; 13 | veci = v; 14 | 15 | printf("%.1f %.1f %.1f\n", vecf.x, vecf.y, vecf.z); 16 | printf("%.1f %.1f %.1f\n", vecd.x, vecd.y, vecd.z); 17 | printf("%i %i %i\n", veci.x, veci.y, veci.z); 18 | printf("%i %i %i\n", v.x, v.y, v.z); 19 | } 20 | -------------------------------------------------------------------------------- /tests/functional/issues/issue34.stdout: -------------------------------------------------------------------------------- 1 | 0.0 0.0 0.0 2 | 0.0 0.0 0.0 3 | 0 0 0 4 | 0 0 0 5 | -------------------------------------------------------------------------------- /tests/functional/issues/issue35.kit: -------------------------------------------------------------------------------- 1 | struct TupleContainer[A, B] { 2 | public var data: Array[(A, B)]; 3 | 4 | public static function new() { 5 | var data = Array.new(10); 6 | return struct TupleContainer[A, B] { 7 | data, 8 | }; 9 | } 10 | } 11 | 12 | struct Pair[A, B] { 13 | public var a: A; 14 | public var b: B; 15 | } 16 | 17 | struct StructContainer[A, B] { 18 | public var data: Array[Pair[A, B]]; 19 | 20 | public static function new(): StructContainer[A, B] { 21 | var data: Array[Pair[A, B]] = Array.new(10); 22 | return struct Self { 23 | data, 24 | }; 25 | } 26 | } 27 | 28 | function main() { 29 | var x = TupleContainer[Int, Float].new(); 30 | x.data[0][0] = 1; 31 | x.data[0][1] = 2.3; 32 | var y = StructContainer[Float, Int].new(); 33 | y.data[0].a = 4.5; 34 | y.data[0].b = 6; 35 | 36 | printf("%i %.1f %.1f %i\n", x.data[0][0], x.data[0][1], y.data[0].a, y.data[0].b); 37 | } 38 | -------------------------------------------------------------------------------- /tests/functional/issues/issue35.sdout: -------------------------------------------------------------------------------- 1 | 1 2.3 4.5 6 2 | -------------------------------------------------------------------------------- /tests/functional/issues/issue37.kit: -------------------------------------------------------------------------------- 1 | using rules MyRules; 2 | using implicit ("a", "b", "c"); 3 | 4 | rules MyRules { 5 | (SOMETHING) => printf("it worked\n"); 6 | } 7 | 8 | function testFunc(x: (CString, CString, CString)) { 9 | printf("%s %s %s\n", x[0], x[1], x[2]); 10 | } 11 | 12 | function main() { 13 | testFunc(); 14 | SOMETHING; 15 | } 16 | -------------------------------------------------------------------------------- /tests/functional/issues/issue37.stdout: -------------------------------------------------------------------------------- 1 | a b c 2 | it worked 3 | -------------------------------------------------------------------------------- /tests/functional/issues/issue4.kit: -------------------------------------------------------------------------------- 1 | trait MyTrait { 2 | public function echo(): Void; 3 | } 4 | 5 | implement MyTrait for Int { 6 | public function echo() { 7 | printf("hello from Int %i\n", this); 8 | } 9 | } 10 | 11 | function main() { 12 | var a: Int = 10; 13 | // This will create a temp variable which relies on A, so temp variable 14 | // generation must be in the correct order or the generated code won't 15 | // compile. 16 | (((a + 5) as Int) as Box[MyTrait]).echo(); 17 | } 18 | -------------------------------------------------------------------------------- /tests/functional/issues/issue4.stdout: -------------------------------------------------------------------------------- 1 | hello from Int 15 2 | -------------------------------------------------------------------------------- /tests/functional/issues/issue57.kit: -------------------------------------------------------------------------------- 1 | import kit.vector; 2 | import kit.map; 3 | 4 | trait Component { 5 | function typeIdentifier(): CString; 6 | } 7 | 8 | struct Entity { 9 | private var components: Map[CString, Box[Component]]; 10 | public var name: CString; 11 | 12 | public static function new(allocator: Box[Allocator], name: CString): Entity using implicit allocator { 13 | var components = Map.new(10); 14 | return struct Self 15 | { 16 | components, 17 | name, 18 | }; 19 | } 20 | 21 | public function addComponent(component: Box[Component]) { 22 | if this.components.exists(component.typeIdentifier()) { 23 | this.components.put(component.typeIdentifier(), component); 24 | } else { 25 | this.components.remove(component.typeIdentifier()); 26 | this.components.put(component.typeIdentifier(), component); 27 | } 28 | } 29 | 30 | public function getComponent(typeIdentifier: CString) { 31 | if this.components.exists(typeIdentifier) { 32 | return this.components.get(typeIdentifier).unwrap(); 33 | } else { 34 | panic("component doesn't exist"); 35 | } 36 | } 37 | } 38 | 39 | struct PositionComponent{ 40 | var x: Float; 41 | var y: Float; 42 | var z: Float; 43 | } 44 | 45 | implement Component for PositionComponent { 46 | function typeIdentifier(): CString { 47 | return "Position"; 48 | } 49 | } 50 | 51 | function main() { 52 | var entity1: Entity = Entity.new("Apple"); 53 | var entity2: Entity = Entity.new("Orange"); 54 | 55 | var positionComponent = struct PositionComponent{ 56 | x: 12.0, 57 | y: 12.0, 58 | z: 12.0 59 | }; 60 | 61 | var boxComponent: Box[Component] = positionComponent; 62 | entity1.addComponent(boxComponent); 63 | 64 | var returnedBoxedComponent: Box[Component] = entity1.getComponent("Position"); 65 | } 66 | -------------------------------------------------------------------------------- /tests/functional/issues/issue6.kit: -------------------------------------------------------------------------------- 1 | struct GenericStruct[T, $N] { 2 | public static function staticFunction(): T { 3 | return 1; 4 | } 5 | 6 | rules { 7 | ($this.capacity) => N as Size; 8 | } 9 | 10 | public var data: CArray[T, N] = empty; 11 | 12 | public function testFunc(): T { 13 | return this.data[0]; 14 | } 15 | 16 | public function zero(): T { 17 | var x: CArray[T, N] = empty; 18 | return x[0]; 19 | } 20 | } 21 | 22 | function main() { 23 | var a = struct GenericStruct[Int, 1]; 24 | var b = struct GenericStruct[Float, 2]; 25 | var c = struct GenericStruct[Int, 3]; 26 | a.data[0] = 1; 27 | b.data[0] = 2.5; 28 | b.data[1] = 3.5; 29 | 30 | printf("%zu\n", a.capacity); 31 | printf("%zu\n", b.capacity); 32 | printf("%zu\n", c.capacity); 33 | 34 | printf(if sizeof GenericStruct[Int, 1] < sizeof GenericStruct[Float, 2] then "smaller; expected\n" else "bigger; unexpected\n"); 35 | printf("%i\n", a.testFunc()); 36 | printf("%.2f\n", b.testFunc()); 37 | 38 | printf("%i\n", a.zero()); 39 | printf("%.2f\n", b.zero()); 40 | 41 | var e = GenericStruct[Int, 4].staticFunction(); 42 | var f = GenericStruct[Int, 7].staticFunction(); 43 | } 44 | -------------------------------------------------------------------------------- /tests/functional/issues/issue6.stdout: -------------------------------------------------------------------------------- 1 | 1 2 | 2 3 | 3 4 | smaller; expected 5 | 1 6 | 2.50 7 | 0 8 | 0.00 9 | -------------------------------------------------------------------------------- /tests/functional/issues/issue60.kit: -------------------------------------------------------------------------------- 1 | function main() { 2 | var localInt = 1; 3 | var localIntPtr: Ptr[Int] = localInt; 4 | var sharedInt = localIntPtr as Shared[Int]; 5 | var sharedIntPtr: Ptr[Shared[Int]] = sharedInt; 6 | 7 | var x: Shared[Void] = Shared.alloc(sizeof Int); 8 | *(x as Ptr[Int]) = 5; 9 | printf("%i\n", *(x as Ptr[Int])); 10 | x.release(); 11 | 12 | // the fix for #60 could break this: 13 | var a: Int = 1; 14 | var b: Ptr[Const[Int]] = a; 15 | } 16 | -------------------------------------------------------------------------------- /tests/functional/issues/issue75.kit: -------------------------------------------------------------------------------- 1 | // these enum constructors conflict with Int type parameter names 2 | enum MyEnum { 3 | N; 4 | T; 5 | W; 6 | } 7 | 8 | struct Struct1[T] { 9 | var x: Struct2[T]; 10 | 11 | public static function new(y: T) { 12 | return struct Self { 13 | x: Struct2[T].new(y), 14 | }; 15 | } 16 | } 17 | 18 | struct Struct2[T] { 19 | var y: T; 20 | 21 | public static function new(y: T) { 22 | return struct Self {y}; 23 | } 24 | } 25 | 26 | function main() { 27 | var i: Int = 1; 28 | printf("%i\n", i); 29 | 30 | var s = Struct1[CString].new("hi"); 31 | printf("%s\n", s.x.y); 32 | } 33 | -------------------------------------------------------------------------------- /tests/functional/issues/issue75.stdout: -------------------------------------------------------------------------------- 1 | 1 2 | hi 3 | -------------------------------------------------------------------------------- /tests/functional/issues/issue8.kit: -------------------------------------------------------------------------------- 1 | function main() { 2 | var a; 3 | var b: Ptr[Void] = &a; 4 | a = 1; 5 | } 6 | -------------------------------------------------------------------------------- /tests/functional/issues/issue80.kit: -------------------------------------------------------------------------------- 1 | import kit.map; 2 | import kit.array; 3 | 4 | trait Component{ 5 | function type(): CString; 6 | } 7 | 8 | struct PositionComponent{ 9 | public var x: Int; 10 | public var y: Int; 11 | public var z: Int; 12 | } 13 | 14 | implement Component for PositionComponent{ 15 | function type(): CString{ 16 | return "Position"; 17 | } 18 | } 19 | 20 | function main() { 21 | 22 | var myMap: Map[CString, Box[Component]] = Map.new(10); 23 | 24 | var myPosStruct = struct PositionComponent{ 25 | x: 12, 26 | y: 12, 27 | z: 23 28 | }; 29 | 30 | var myPosStructBox: Box[Component] = myPosStruct; 31 | myMap.put(myPosStructBox.type(), myPosStructBox); 32 | 33 | var keys = myMap.keys(); 34 | var constructed = CString.alloc("Position".length); 35 | var i = 0; 36 | for char in "Position" { 37 | constructed[i++] = char; 38 | } 39 | printf("key: %s\n", constructed); 40 | 41 | printf("box.type(): %s\n", if myMap.exists(myPosStructBox.type()) then "true" else "false"); 42 | printf("keys[0]: %s\n", if myMap.exists(keys[0]) then "true" else "false"); 43 | printf("literal: %s\n", if myMap.exists("Position") then "true" else "false"); 44 | printf("buffer: %s\n", if myMap.exists(constructed) then "true" else "false"); 45 | } 46 | -------------------------------------------------------------------------------- /tests/functional/issues/issue80.stdout: -------------------------------------------------------------------------------- 1 | key: Position 2 | box.type(): true 3 | keys[0]: true 4 | literal: true 5 | buffer: true 6 | -------------------------------------------------------------------------------- /tests/functional/issues/issue87.kit: -------------------------------------------------------------------------------- 1 | struct MyStruct { 2 | public var a: Int; 3 | public var b: Int; 4 | } 5 | 6 | function main() { 7 | var n: Int = 0x1000; 8 | var a: Array[MyStruct] = Array.new(n * 2); 9 | var v: Vector[Ptr[MyStruct]] = Vector.new(n); 10 | 11 | for i in 0 ... n * 2 { 12 | var x: Ptr[MyStruct] = a[i]; 13 | v.push(x); 14 | } 15 | 16 | printf("%zx\n", v.length); 17 | } 18 | -------------------------------------------------------------------------------- /tests/functional/issues/issue87.stdout: -------------------------------------------------------------------------------- 1 | 2000 2 | -------------------------------------------------------------------------------- /tests/functional/issues/issue93.kit: -------------------------------------------------------------------------------- 1 | function main() { 2 | var array: Array[Array[Int]] = Array.new(4); 3 | array[0] = Array.new(4); 4 | array[0][0] = 7; 5 | printf("%i\n", array[0][0]); 6 | 7 | var array2: Vector[Array[Array[Array[Int]]]] = Vector.new(4); 8 | array2[0] = Array.new(2); 9 | array2[0][1] = Array.new(3); 10 | array2[0][1][2] = Array.new(4); 11 | array2[0][1][2][3] = 11; 12 | printf("%i\n", array2[0][1][2][3]); 13 | 14 | var m3: Map[CString, Array[Int]]; 15 | m3 = Map.new(8); 16 | var a = Array.new(8); 17 | a[0] = 15; 18 | m3.put("abc", a); 19 | var a2 = m3["abc"]; 20 | printf("%i\n", a2[0]); 21 | } 22 | -------------------------------------------------------------------------------- /tests/functional/issues/issue93.stdout: -------------------------------------------------------------------------------- 1 | 7 2 | 11 3 | 15 4 | -------------------------------------------------------------------------------- /tests/functional/issues/issue96.kit: -------------------------------------------------------------------------------- 1 | trait MyTrait; 2 | 3 | trait OtherTrait { 4 | function getHash(): Int; 5 | } 6 | 7 | implement MyTrait for Int; 8 | implement MyTrait for Char; 9 | 10 | implement OtherTrait for MyTrait { 11 | function getHash(): Int { 12 | return this; 13 | } 14 | } 15 | 16 | function main() { 17 | var i: Int = 1; 18 | var c: Char = 2; 19 | printf("%i %i\n", i.OtherTrait.getHash(), c.OtherTrait.getHash()); 20 | } 21 | -------------------------------------------------------------------------------- /tests/functional/issues/issue96.stdout: -------------------------------------------------------------------------------- 1 | 1 2 2 | -------------------------------------------------------------------------------- /tests/functional/issues/issue97.kit: -------------------------------------------------------------------------------- 1 | function f(): Option[Int] { 2 | return Some(1); 3 | } 4 | 5 | function main() { 6 | var result = f(); 7 | match result { 8 | Some(result) => { 9 | printf("%i\n", result); 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /tests/functional/issues/issue97.stdout: -------------------------------------------------------------------------------- 1 | 1 2 | -------------------------------------------------------------------------------- /tests/functional/literals.kit: -------------------------------------------------------------------------------- 1 | function main() { 2 | printf("\x0a\x61\x70\x70\x6c\x65\x0a"); 3 | for char in [ 4 | c'a', 5 | c'1', 6 | c'\\', 7 | c'\'', 8 | c'\t', 9 | ] { 10 | printf("%c.\n", char); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /tests/functional/literals.stdout: -------------------------------------------------------------------------------- 1 | 2 | apple 3 | a. 4 | 1. 5 | \. 6 | '. 7 | . 8 | -------------------------------------------------------------------------------- /tests/functional/macros.kit: -------------------------------------------------------------------------------- 1 | macro generateStruct() { 2 | puts(""" 3 | struct GeneratedStruct { 4 | public var a: Int; 5 | public var b: Float; 6 | } 7 | """); 8 | } 9 | 10 | macro extendStruct(field: CString, type: CString) { 11 | printf(""" 12 | extend GeneratedStruct { 13 | public var %s: %s; 14 | } 15 | """, field, type); 16 | } 17 | 18 | macro prefixAString(s: CString) { 19 | printf('"Mr. %s"', s); 20 | } 21 | 22 | generateStruct(); 23 | extendStruct("c", "Int"); 24 | extendStruct("d", "CString"); 25 | 26 | macro makeAFunction(name: CString) { 27 | printf(""" 28 | function %s() { 29 | printf("hello from function %s!\\n"); 30 | } 31 | """, name, name); 32 | } 33 | 34 | makeAFunction("helloWorld"); 35 | 36 | macro boldify(s: CString) { 37 | printf('"** %s **"', s); 38 | } 39 | 40 | function main() { 41 | var x = struct GeneratedStruct { 42 | a: 1, 43 | b: 2.0, 44 | c: 3, 45 | d: "hi", 46 | }; 47 | 48 | printf("%i %.1f %i %s\n", x.a, x.b, x.c, x.d); 49 | 50 | helloWorld(); 51 | 52 | puts(prefixAString("Lincoln")); 53 | puts(boldify("HELLO!")); 54 | } 55 | -------------------------------------------------------------------------------- /tests/functional/macros.stdout: -------------------------------------------------------------------------------- 1 | 1 2.0 3 hi 2 | hello from function helloWorld! 3 | Mr. Lincoln 4 | ** HELLO! ** 5 | -------------------------------------------------------------------------------- /tests/functional/match.stdout: -------------------------------------------------------------------------------- 1 | default 2 | one 3 | two 4 | three 5 | default 6 | true 7 | false 8 | match true: correct 9 | match false: correct 10 | bool match: default 11 | bool match: default 12 | one 13 | two 14 | apple 15 | banana 16 | something else 17 | APPLE 18 | BANANA 19 | something else 20 | 1.5 21 | 2.5 22 | something else 23 | an apple 24 | 3 apples 25 | a bunch of 3 bananas 26 | 4 bunches of 5 bananas 27 | some grapes 28 | ??? 29 | a box of apples 30 | 2 boxes of apples 31 | 2 boxes of bananas 32 | ??? 33 | a is 1 34 | d is 3 35 | hi 36 | hello world 37 | -------------------------------------------------------------------------------- /tests/functional/methods.kit: -------------------------------------------------------------------------------- 1 | struct MyStruct { 2 | public var a: Int16; 3 | 4 | public function myMethod() { 5 | printf("a = %i\n", this.a); 6 | } 7 | } 8 | 9 | function staticExtension(m: MyStruct, i: Int) { 10 | printf("static extension called with %i and %i\n", m.a, i); 11 | } 12 | 13 | function main() { 14 | var s1 = struct MyStruct {a: 1}; 15 | s1.myMethod(); 16 | var s2 = struct MyStruct {a: 2}; 17 | MyStruct.myMethod(s2); 18 | var s3 = struct MyStruct {a: 3}; 19 | using implicit s3 { 20 | MyStruct.myMethod(); 21 | } 22 | 23 | staticExtension(s1, 5); 24 | s2.staticExtension(6); 25 | } 26 | -------------------------------------------------------------------------------- /tests/functional/methods.stdout: -------------------------------------------------------------------------------- 1 | a = 1 2 | a = 2 3 | a = 3 4 | static extension called with 1 and 5 5 | static extension called with 2 and 6 6 | -------------------------------------------------------------------------------- /tests/functional/modulevars.kit: -------------------------------------------------------------------------------- 1 | var a: Int = 1; 2 | var b = 2; 3 | 4 | function main() { 5 | var c: Float = a + b; 6 | } 7 | -------------------------------------------------------------------------------- /tests/functional/operator.kit: -------------------------------------------------------------------------------- 1 | function main() { 2 | var s = -sin(0); 3 | printf("%.2f\n", s); 4 | } 5 | -------------------------------------------------------------------------------- /tests/functional/operator.stdout: -------------------------------------------------------------------------------- 1 | -0.00 2 | -------------------------------------------------------------------------------- /tests/functional/param_inference.kit: -------------------------------------------------------------------------------- 1 | struct MyStruct[T] { 2 | var m: Map[Int, T]; 3 | } 4 | 5 | function main() { 6 | var m: Map = Map.new(16); 7 | m.put(16, "hello"); 8 | var s = m[16]; 9 | puts(s); 10 | 11 | var m2: Map; 12 | m2 = Map.new(4); 13 | m2.put(true, 1); 14 | m2.put(false, 2); 15 | var i = m2[true]; 16 | printf("%i\n", i); 17 | 18 | var st = struct MyStruct { 19 | m: Map.new(4) 20 | }; 21 | st.m.put(1, 5); 22 | printf("%i\n", st.m[1]); 23 | } 24 | -------------------------------------------------------------------------------- /tests/functional/param_inference.stdout: -------------------------------------------------------------------------------- 1 | hello 2 | 1 3 | 5 4 | -------------------------------------------------------------------------------- /tests/functional/pointers.kit: -------------------------------------------------------------------------------- 1 | function main() { 2 | var a = 1; 3 | var b: &Int = a; 4 | printf("%i\n", *b); 5 | 6 | var c = 2.5; 7 | var d: Ptr[Float] = c; 8 | printf("%.1f\n", *d); 9 | 10 | var e = b[0]; 11 | printf("%i\n", e); 12 | } 13 | -------------------------------------------------------------------------------- /tests/functional/pointers.stdout: -------------------------------------------------------------------------------- 1 | 1 2 | 2.5 3 | 1 4 | -------------------------------------------------------------------------------- /tests/functional/reserved_words.kit: -------------------------------------------------------------------------------- 1 | function main() { 2 | var @while = "while"; 3 | var @do = "do"; 4 | 5 | printf("%s %s\n", @while, @do); 6 | 7 | var @true = true; 8 | var @false = false; 9 | 10 | if @true { 11 | printf("true\n"); 12 | } 13 | if @false { 14 | printf("false\n"); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /tests/functional/reserved_words.stdout: -------------------------------------------------------------------------------- 1 | while do 2 | true 3 | -------------------------------------------------------------------------------- /tests/functional/rewrite.kit: -------------------------------------------------------------------------------- 1 | include "math.h"; 2 | 3 | rules MyRewriteRules { 4 | ("a specific string") => printf("%s\n", "got replaced"); 5 | (5) => 6; 6 | (${x: Int} %% 1) => $x + 1; 7 | (apple) => true; 8 | (banana) => strawberry; 9 | } 10 | 11 | function a(): Double { 12 | printf("side effect a\n"); 13 | return 1; 14 | } 15 | 16 | function b(): Double { 17 | printf("side effect b\n"); 18 | return 2; 19 | } 20 | 21 | rules Reduce { 22 | (pow($x + $y, 2)) => (pow($x, 2) + 2 * $x * $y + pow($y, 2)); 23 | } 24 | 25 | struct MyStruct { 26 | var myField: Int; 27 | 28 | rules { 29 | ($this.property) => $this.myField; 30 | } 31 | } 32 | 33 | trait MyTrait { 34 | public function doSomething(): Void; 35 | 36 | rules { 37 | ($this.propertyWithSideEffects) => $this.doSomething(); 38 | (for i in $this {$e}) => { 39 | printf("%s\n", "tried to iterate over MyTrait"); 40 | $this.doSomething(); 41 | $e; 42 | } 43 | } 44 | } 45 | 46 | implement MyTrait for MyStruct { 47 | public function doSomething() { 48 | printf("%s\n", "this is MyStruct's MyTrait implementation"); 49 | } 50 | } 51 | 52 | function main() { 53 | printf("%i\n", 5_i32); 54 | 55 | using rules MyRewriteRules { 56 | var a = "a specific string"; 57 | var b = "some other string"; 58 | 59 | // custom operator; must be rewritten or will fail to compile 60 | var x: Int = 5; 61 | // var x = 5_i32; 62 | printf("%i\n", x); 63 | printf("%i\n", x %% 1); 64 | 65 | // var doesn't exist; must be rewritten or will fail to compile 66 | if (apple) { 67 | printf("apple => true\n"); 68 | } 69 | 70 | var strawberry = true; 71 | if (banana) { 72 | printf("banana => strawberry\n"); 73 | } 74 | } 75 | 76 | using rules Reduce { 77 | var a: Double = pow(a() + b(), 2); 78 | printf("%.2f\n", a); 79 | } 80 | 81 | var s = struct MyStruct {myField: 5}; 82 | printf("%i\n", s.myField); 83 | printf("%i\n", s.property); 84 | 85 | var box: Box[MyTrait] = s; 86 | box.propertyWithSideEffects; 87 | for i in box { 88 | printf("hello\n"); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /tests/functional/rewrite.stdout: -------------------------------------------------------------------------------- 1 | 5 2 | got replaced 3 | 6 4 | 7 5 | apple => true 6 | banana => strawberry 7 | side effect a 8 | side effect a 9 | side effect b 10 | side effect b 11 | 9.00 12 | 5 13 | 5 14 | this is MyStruct's MyTrait implementation 15 | tried to iterate over MyTrait 16 | this is MyStruct's MyTrait implementation 17 | hello 18 | -------------------------------------------------------------------------------- /tests/functional/sizeof.kit: -------------------------------------------------------------------------------- 1 | struct MyStruct1 { 2 | var a: Int32; 3 | var b: Int32; 4 | } 5 | 6 | struct MyStruct2 { 7 | var a: Int32; 8 | var b: Int64; 9 | } 10 | 11 | struct MyStruct3 { 12 | var a: Int64; 13 | var b: Int64; 14 | } 15 | 16 | function main() { 17 | var x: Int = sizeof Ptr[MyStruct1]; 18 | printf("%i\n", x); 19 | printf("%lu\n", sizeof MyStruct1); 20 | printf("%lu\n", sizeof MyStruct2); 21 | printf("%lu\n", sizeof MyStruct3); 22 | printf("%lu\n", sizeof Bool); 23 | printf("%lu\n", sizeof Int8); 24 | printf("%lu\n", sizeof Uint8); 25 | printf("%lu\n", sizeof Int16); 26 | printf("%lu\n", sizeof Uint16); 27 | printf("%lu\n", sizeof Int32); 28 | printf("%lu\n", sizeof Uint32); 29 | printf("%lu\n", sizeof Float32); 30 | printf("%lu\n", sizeof Int64); 31 | printf("%lu\n", sizeof Uint64); 32 | printf("%lu\n", sizeof Float64); 33 | } 34 | -------------------------------------------------------------------------------- /tests/functional/static_if.kit: -------------------------------------------------------------------------------- 1 | function main() { 2 | static if true { 3 | puts("true"); 4 | } else { 5 | puts("???"); 6 | } 7 | 8 | static if false { 9 | puts("???"); 10 | } else { 11 | puts("not false"); 12 | } 13 | 14 | var x = true; 15 | static if x { 16 | puts("x = true"); 17 | } else { 18 | puts("x = false"); 19 | } 20 | 21 | // x = false; 22 | // static if x { 23 | // puts("x = true"); 24 | // } else { 25 | // puts("x = false"); 26 | // } 27 | 28 | static if 1 == 1 { 29 | puts("1. 1 == 1"); 30 | } else { 31 | puts("1. 1 != 1"); 32 | } 33 | 34 | static if 1 != 1 { 35 | puts("2. 1 != 1"); 36 | } else { 37 | puts("2. 1 == 1"); 38 | } 39 | 40 | static if 1 == 1 { 41 | puts("3. 1 == 1"); 42 | } 43 | 44 | static if 1 != 1 { 45 | puts("4. 1 != 1"); 46 | } 47 | 48 | printf("%i\n", static 1 + 1); 49 | // printf("%d.2\n", static 3.141592654 * 2); 50 | } 51 | -------------------------------------------------------------------------------- /tests/functional/static_if.stdout: -------------------------------------------------------------------------------- 1 | true 2 | not false 3 | x = true 4 | 1. 1 == 1 5 | 2. 1 == 1 6 | 3. 1 == 1 7 | 2 8 | -------------------------------------------------------------------------------- /tests/functional/static_init.kit: -------------------------------------------------------------------------------- 1 | function f() { 2 | return "hello"; 3 | } 4 | 5 | struct MyStruct { 6 | public static var x = f(); 7 | public static var y = Self.f(); 8 | 9 | var a: Int = 0; 10 | 11 | static function f() { 12 | return "world"; 13 | } 14 | } 15 | 16 | function main() { 17 | printf("%s %s!\n", MyStruct.x, MyStruct.y); 18 | } 19 | -------------------------------------------------------------------------------- /tests/functional/static_init.stdout: -------------------------------------------------------------------------------- 1 | hello world! 2 | -------------------------------------------------------------------------------- /tests/functional/staticmethods.kit: -------------------------------------------------------------------------------- 1 | struct MyStruct { 2 | var a: Int; 3 | public static function myStaticMethod() { 4 | printf("hello"); 5 | } 6 | } 7 | 8 | struct MyStruct2 { 9 | var b: Int; 10 | public static function myStaticMethod() { 11 | printf(" world!\n"); 12 | } 13 | } 14 | 15 | function main() { 16 | MyStruct.myStaticMethod(); 17 | MyStruct2.myStaticMethod(); 18 | } 19 | -------------------------------------------------------------------------------- /tests/functional/staticmethods.stdout: -------------------------------------------------------------------------------- 1 | hello world! 2 | -------------------------------------------------------------------------------- /tests/functional/std/array.kit: -------------------------------------------------------------------------------- 1 | function gt3(i: Ptr[Int]) { 2 | return *i > 3; 3 | } 4 | 5 | function main() { 6 | printf("original\n"); 7 | var a: Array[Int] = Array[Int].new(4); 8 | printf("length = %zu\n", a.length); 9 | a[0] = 11; 10 | a[1] = 23; 11 | a[2] = 35; 12 | a[3] = 47; 13 | // a = [1, 2, 3, 4]; 14 | printf("first element = %i\n", a[0]); 15 | printf("second element = %i\n", a[1]); 16 | printf("third element = %i\n", a[2]); 17 | printf("fourth element = %i\n", a[3]); 18 | for x in a { 19 | printf("iterating: %i\n", x); 20 | } 21 | 22 | printf("copy\n"); 23 | var a2: Array[Int] = a.copy(); 24 | printf("length = %zu\n", a2.length); 25 | printf("first element = %i\n", a2[0]); 26 | printf("third element = %i\n", a2[2]); 27 | for x in a2 { 28 | printf("%i\n", x); 29 | } 30 | 31 | { 32 | var a1: Array[Int] = Array.new(3); 33 | a1[0] = 1; 34 | a1[1] = 3; 35 | a1[2] = 5; 36 | 37 | var a2: Array[Int] = Array.new(3); 38 | a2[0] = 5; 39 | a2[1] = 6; 40 | a2[2] = 7; 41 | 42 | var a3: Array[Int] = Array.new(3); 43 | a3[0] = 0; 44 | a3[1] = 1; 45 | a3[2] = 2; 46 | 47 | for a in [a1, a2, a3] { 48 | puts(if a.any(gt3) then "any = true" else "any = false"); 49 | puts(if a.all(gt3) then "all = true" else "all = false"); 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /tests/functional/std/array.stdout: -------------------------------------------------------------------------------- 1 | original 2 | length = 4 3 | first element = 11 4 | second element = 23 5 | third element = 35 6 | fourth element = 47 7 | iterating: 11 8 | iterating: 23 9 | iterating: 35 10 | iterating: 47 11 | copy 12 | length = 4 13 | first element = 11 14 | third element = 35 15 | 11 16 | 23 17 | 35 18 | 47 19 | any = true 20 | all = false 21 | any = true 22 | all = true 23 | any = false 24 | all = false 25 | -------------------------------------------------------------------------------- /tests/functional/std/either.kit: -------------------------------------------------------------------------------- 1 | function main() { 2 | var a: Either[Int, CString] = Left(123); 3 | 4 | match a { 5 | Left(x) => { 6 | printf("expected: %i\n", x); 7 | } 8 | default => { 9 | printf("unexpected!\n"); 10 | } 11 | } 12 | 13 | a = Right("stringvalue"); 14 | match a { 15 | Right(x) => { 16 | printf("expected: %s\n", x); 17 | } 18 | default => { 19 | printf("unexpected!\n"); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /tests/functional/std/either.stdout: -------------------------------------------------------------------------------- 1 | expected: 123 2 | expected: stringvalue 3 | -------------------------------------------------------------------------------- /tests/functional/std/iterator.stdout: -------------------------------------------------------------------------------- 1 | list iterator manual iteration 2 | length = 3 3 | list iterator: next 4 | returning 1 5 | list iterator: next 6 | returning 2 7 | list iterator: next 8 | returning 3 9 | list iterator: next 10 | empty 11 | list iterator for loop iteration 12 | length = 3 13 | for loop over collection: 1 14 | for loop over collection: 2 15 | for loop over collection: 3 16 | done 17 | list iterator: next 18 | returning 1 19 | for loop over iterator: 1 20 | list iterator: next 21 | returning 2 22 | for loop over iterator: 2 23 | list iterator: next 24 | returning 3 25 | for loop over iterator: 3 26 | list iterator: next 27 | empty 28 | done 29 | struct iterator for loop iteration 30 | length = 3 31 | struct iterator: next 32 | returning 1 33 | struct iterator: next 34 | returning 2 35 | struct iterator: next 36 | returning 3 37 | struct iterator: next 38 | empty 39 | struct iterator manual iteration 40 | length = 3 41 | struct iterator: next 42 | returning 1 43 | struct iterator: next 44 | returning 2 45 | for loop over iterable: 2 46 | struct iterator: next 47 | returning 3 48 | for loop over iterable: 3 49 | struct iterator: next 50 | empty 51 | done 52 | -------------------------------------------------------------------------------- /tests/functional/std/list.kit: -------------------------------------------------------------------------------- 1 | abstract PrintingList: List[Int] { 2 | public function print() { 3 | var current: List[Int] = this; 4 | while true { 5 | match current { 6 | Cons(h, t) => { 7 | printf("%i ", h); 8 | current = *t; 9 | } 10 | default => break; 11 | } 12 | } 13 | printf(".\n"); 14 | } 15 | } 16 | 17 | function main() { 18 | var l: List[Int] = Empty; 19 | var m: List[Int] = Cons(1, &l); 20 | var n: List[Int] = Cons(2, &m); 21 | var o = n.cons(3); 22 | 23 | var len: Size = l.length; 24 | printf("%lu\n", len); 25 | printf("%lu\n", o.getLength()); 26 | printf("%lu\n", n.length); 27 | printf("%lu\n", List.getLength(m)); 28 | printf("%lu\n", List[Int].getLength(m)); 29 | 30 | var l2: PrintingList = l as PrintingList; 31 | var m2: PrintingList = m as PrintingList; 32 | var n2: PrintingList = n as PrintingList; 33 | var o2: PrintingList = o as PrintingList; 34 | 35 | l2.print(); 36 | m2.print(); 37 | n2.print(); 38 | o2.print(); 39 | } 40 | -------------------------------------------------------------------------------- /tests/functional/std/list.stdout: -------------------------------------------------------------------------------- 1 | 0 2 | 3 3 | 2 4 | 1 5 | 1 6 | . 7 | 1 . 8 | 2 1 . 9 | 3 2 1 . 10 | -------------------------------------------------------------------------------- /tests/functional/std/map.stdout: -------------------------------------------------------------------------------- 1 | Capacity: 10 2 | Size: 0 3 | Key Exists 'test1': false 4 | First value added: 1 5 | Size: 1 6 | Key Exists 'test1': true 7 | Size after removing single element: 0 8 | Key Exists 'test1': false 9 | Value added: 3 10 | Value added: 4 11 | Value added: 5 12 | Size after adding three elements: 3 13 | Value added: 6 14 | Size after adding duplicate element: 3 15 | Key Exists 'test2': true 16 | Key Exists 'test3': true 17 | Key Exists 'test5': false 18 | Get 3: 3 19 | Get 4: 4 20 | Get 5: 6 21 | Quick Get 3: 3 22 | Array size of map keys: 3 23 | Array contains 'test2': true 24 | Map resizes if more than threshold is added, capacity is greater: 15 25 | Key Exists 'test2': true 26 | Key Exists 'test3': true 27 | Key Exists 'test5': false 28 | Key 1 Exists: true 29 | Key 2 Exists: true 30 | Key 1 Exists: false 31 | Key 2 Exists: true 32 | -------------------------------------------------------------------------------- /tests/functional/std/math.kit: -------------------------------------------------------------------------------- 1 | function main() { 2 | var i1: Int = max(1, 2); 3 | var i2: Int = max(2, 1); 4 | var f: Float = min(1, 2); 5 | printf("%i\n", i1); 6 | printf("%i\n", i2); 7 | printf("%.2f\n", f); 8 | } 9 | -------------------------------------------------------------------------------- /tests/functional/std/math.stdout: -------------------------------------------------------------------------------- 1 | 2 2 | 2 3 | 1.00 4 | -------------------------------------------------------------------------------- /tests/functional/std/mem.stdout: -------------------------------------------------------------------------------- 1 | testing linear allocator 2 | got a pointer 3 | remaining: 1 4 | got a pointer 5 | remaining: 0 6 | didn't get a pointer 7 | remaining: 0 8 | after reset, they're the same as expected 9 | testing stack allocator 10 | got a pointer 11 | remaining: 2 12 | got a pointer 13 | remaining: 1 14 | got a pointer 15 | remaining: 0 16 | didn't get a pointer 17 | remaining: 0 18 | after free, they're the same as expected 19 | remaining: 1 20 | remaining: 1 21 | remaining: 1 22 | remaining: 0 23 | via box, they're the same as expected 24 | testing pool allocator 25 | got a pointer 26 | got a pointer 27 | didn't get a pointer 28 | got a pointer 29 | recycled pointer reused as expected 30 | didn't get a pointer 31 | 15 15 32 | 20 0 33 | 0 34 | -------------------------------------------------------------------------------- /tests/functional/std/numeric.kit: -------------------------------------------------------------------------------- 1 | function main() { 2 | var a = 127_i8; 3 | var a2 = 127; 4 | var b = 255_u8; 5 | var c = 32767_i16; 6 | var d = 100000; 7 | var e = 127_u64; 8 | var f = 127_f32; 9 | var g = 100_s; 10 | 11 | if ++a == -128 { 12 | printf("a overflow\n"); 13 | } 14 | if ++a2 == 128 { 15 | printf("no a2 overflow\n"); 16 | } 17 | if ++b == 0 { 18 | printf("b overflow\n"); 19 | } 20 | if ++c == -32768 { 21 | printf("c overflow\n"); 22 | } 23 | if ++d == 100001 { 24 | printf("no d overflow\n"); 25 | } 26 | if ++e == 0 { 27 | printf("e overflow\n"); 28 | } 29 | f += 1.0; 30 | printf("%.1f\n", f); 31 | printf("%zu\n", g); 32 | 33 | printf((```"Int8: %" PRId8 " to %" PRId8 "\n"```: CString), Int8.minValue(), Int8.maxValue()); 34 | printf((```"Int16: %" PRId16 " to %" PRId16 "\n"```: CString), Int16.minValue(), Int16.maxValue()); 35 | printf((```"Int32: %" PRId32 " to %" PRId32 "\n"```: CString), Int32.minValue(), Int32.maxValue()); 36 | printf((```"Int64: %" PRId64 " to %" PRId64 "\n"```: CString), Int64.minValue(), Int64.maxValue()); 37 | printf((```"Uint8: %" PRIu8 " to %" PRIu8 "\n"```: CString), Uint8.minValue(), Uint8.maxValue()); 38 | printf((```"Uint16: %" PRIu16 " to %" PRIu16 "\n"```: CString), Uint16.minValue(), Uint16.maxValue()); 39 | printf((```"Uint32: %" PRIu32 " to %" PRIu32 "\n"```: CString), Uint32.minValue(), Uint32.maxValue()); 40 | printf((```"Uint64: %" PRIu64 " to %" PRIu64 "\n"```: CString), Uint64.minValue(), Uint64.maxValue()); 41 | 42 | printf(if Int.minValue() < Int.maxValue() && Int.minValue() < 0 then "Int: OK\n" else "Int: Broken\n"); 43 | printf(if Uint.minValue() < Uint.maxValue() && Uint.minValue() == 0 then "Uint: OK\n" else "Uint: Broken\n"); 44 | } 45 | -------------------------------------------------------------------------------- /tests/functional/std/numeric.stdout: -------------------------------------------------------------------------------- 1 | a overflow 2 | no a2 overflow 3 | b overflow 4 | c overflow 5 | no d overflow 6 | 128.0 7 | 100 8 | Int8: -128 to 127 9 | Int16: -32768 to 32767 10 | Int32: -2147483648 to 2147483647 11 | Int64: -9223372036854775808 to 9223372036854775807 12 | Uint8: 0 to 255 13 | Uint16: 0 to 65535 14 | Uint32: 0 to 4294967295 15 | Uint64: 0 to 18446744073709551615 16 | Int: OK 17 | Uint: OK 18 | -------------------------------------------------------------------------------- /tests/functional/std/option.kit: -------------------------------------------------------------------------------- 1 | struct MyStruct { 2 | public var a: CString; 3 | } 4 | 5 | function main() { 6 | var a: Option = Some(1); 7 | match a { 8 | Some(i) => { 9 | printf("%i\n", i); 10 | } 11 | default => { 12 | printf("failure\n"); 13 | } 14 | } 15 | a.unwrap(); 16 | 17 | var b: Option[Int] = None; 18 | match b { 19 | Some(i) => { 20 | printf("failure\n"); 21 | } 22 | default => { 23 | printf("success\n"); 24 | } 25 | } 26 | 27 | var c: Int = Some(1) ?? 2; 28 | printf("%i\n", c); 29 | 30 | var d: Int = None ?? 2; 31 | printf("%i\n", d); 32 | 33 | // var s = struct MyStruct {a: "hello"}; 34 | // printf("%s\n", (a ?. hello).unwrap()) 35 | } 36 | -------------------------------------------------------------------------------- /tests/functional/std/option.stdout: -------------------------------------------------------------------------------- 1 | 1 2 | success 3 | 1 4 | 2 5 | -------------------------------------------------------------------------------- /tests/functional/std/pointer.kit: -------------------------------------------------------------------------------- 1 | function main() { 2 | var shared: Shared[CArray[Char, 14]] = Shared.alloc(sizeof CArray[Char, 14]);//Shared.new(); 3 | var sharedString = shared as Ptr[Void] as Shared[CString]; 4 | 5 | (*sharedString) = "hello, world!"; 6 | printf("%s\n", *sharedString); 7 | printf("rc: %zu\n", shared.rc()); 8 | for i in 0 ... 2 { 9 | printf("incrementing ref\n"); 10 | shared.ref(); 11 | printf("rc: %zu\n", shared.rc()); 12 | } 13 | for i in 0 ... 3 { 14 | var released = shared.release(); 15 | printf("released: %s\n", if released then "yes" else "no"); 16 | printf("active: %s\n", if shared.active() then "yes" else "no"); 17 | printf("rc: %zu\n", shared.rc()); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /tests/functional/std/pointer.stdout: -------------------------------------------------------------------------------- 1 | hello, world! 2 | rc: 1 3 | incrementing ref 4 | rc: 2 5 | incrementing ref 6 | rc: 3 7 | released: no 8 | active: yes 9 | rc: 2 10 | released: no 11 | active: yes 12 | rc: 1 13 | released: yes 14 | active: no 15 | rc: 0 16 | -------------------------------------------------------------------------------- /tests/functional/std/random.kit: -------------------------------------------------------------------------------- 1 | import kit.random; 2 | 3 | function main() { 4 | var i = randomRange(1, 5); 5 | if i < 1 || i > 5 { 6 | printf("error: i = %i, should be 1-5\n", i); 7 | } else { 8 | puts("OK"); 9 | } 10 | var f = random(); 11 | if f < 0 || f >= 1 { 12 | printf("error: f = %.1f, should be 0-1\n", f); 13 | } else { 14 | puts("OK"); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /tests/functional/std/random.stdout: -------------------------------------------------------------------------------- 1 | OK 2 | OK 3 | -------------------------------------------------------------------------------- /tests/functional/std/result.kit: -------------------------------------------------------------------------------- 1 | function main() { 2 | var x: Result[Int, CString] = Ok(1); 3 | var y = x.unwrap(); 4 | printf("%i\n", y); 5 | } 6 | -------------------------------------------------------------------------------- /tests/functional/std/result.stdout: -------------------------------------------------------------------------------- 1 | 1 2 | -------------------------------------------------------------------------------- /tests/functional/std/ring_buffer.kit: -------------------------------------------------------------------------------- 1 | import kit.ring_buffer; 2 | 3 | function main() { 4 | var x = RingBuffer.new(4); 5 | printf("ring buffer size: %zu\n", x.length); 6 | x.push(1); 7 | printf("ring buffer size: %zu\n", x.length); 8 | x.push(2); 9 | printf("ring buffer size: %zu\n", x.length); 10 | 11 | printf("items:\n"); 12 | for item in x { 13 | printf("%i\n", item); 14 | } 15 | 16 | for i in 0 ... 3 { 17 | var popped = x.pop(); 18 | match popped { 19 | Some(x) => printf("popped a value: %i\n", x); 20 | None => printf("no more values\n"); 21 | } 22 | printf("ring buffer size: %zu\n", x.length); 23 | } 24 | 25 | for i in 1 ... 6 { 26 | x.push(i); 27 | printf("ring buffer size: %zu\n", x.length); 28 | } 29 | 30 | printf("items:\n"); 31 | for item in x { 32 | printf("%i\n", item); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /tests/functional/std/ring_buffer.stdout: -------------------------------------------------------------------------------- 1 | ring buffer size: 0 2 | ring buffer size: 1 3 | ring buffer size: 2 4 | items: 5 | 1 6 | 2 7 | popped a value: 2 8 | ring buffer size: 1 9 | popped a value: 1 10 | ring buffer size: 0 11 | no more values 12 | ring buffer size: 0 13 | ring buffer size: 1 14 | ring buffer size: 2 15 | ring buffer size: 3 16 | ring buffer size: 4 17 | ring buffer size: 4 18 | items: 19 | 2 20 | 3 21 | 4 22 | 5 23 | -------------------------------------------------------------------------------- /tests/functional/std/set.stdout: -------------------------------------------------------------------------------- 1 | 3,5, 2 | mySet: 1,3,5,8, 3 | 3,5, 4 | 1,3,5,8, 5 | 1,2,3,5,7,8,9, 6 | mySet: 1,3,5,8, 7 | 1,2,3,5,7,8,9, 8 | 1,3,5,8, 9 | 1,8, 10 | mySet: 1,3,5,8, 11 | 1,8, 12 | 1,3,5,8, -------------------------------------------------------------------------------- /tests/functional/std/slice.kit: -------------------------------------------------------------------------------- 1 | function main() { 2 | var arr: CArray[Int, 10] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; 3 | var slice = struct Slice[Int] { 4 | length: arr.length, 5 | data: arr, 6 | }; 7 | 8 | for x in slice { 9 | printf("%i\n", x); 10 | } 11 | 12 | var slice2 = slice[1 ... 5]; 13 | for x in slice2 { 14 | printf("%i\n", x); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /tests/functional/std/slice.stdout: -------------------------------------------------------------------------------- 1 | 1 2 | 2 3 | 3 4 | 4 5 | 5 6 | 6 7 | 7 8 | 8 9 | 9 10 | 10 11 | 2 12 | 3 13 | 4 14 | 5 15 | -------------------------------------------------------------------------------- /tests/functional/std/string.kit: -------------------------------------------------------------------------------- 1 | function main() { 2 | var s: String = String.fromCString("hello, world!"); 3 | printf("length: %zu\n", s.length); 4 | printf("value: %s\n", s.chars); 5 | // var cs = s as CString; 6 | 7 | var buf = StringBuffer.new(16); 8 | buf.add("abc"); 9 | buf.add("def"); 10 | var s2 = buf.toString(); 11 | printf("length: %zu\n", s2.length); 12 | printf("value: %s\n", s2.chars); 13 | 14 | buf.add("ghi"); 15 | var s3 = buf.toString(); 16 | printf("length: %zu\n", s3.length); 17 | printf("value: %s\n", s3.chars); 18 | 19 | for c in s3[1 ... 6] { 20 | printf("%c\n", c); 21 | } 22 | 23 | // var box1: Box[ToString] = *s; 24 | // var box2: Box[ToString] = "hello there!"; 25 | 26 | // FIXME: eventually rewrite rules will allow casting instead of accessing 27 | // `chars` directly 28 | // printf("%s\n", box1.toString().chars); 29 | // printf("%s\n", box2.toString().chars); 30 | 31 | // for cchar in *s { 32 | // printf("%c\n", cchar); 33 | // } 34 | } 35 | -------------------------------------------------------------------------------- /tests/functional/std/string.stdout: -------------------------------------------------------------------------------- 1 | length: 13 2 | value: hello, world! 3 | length: 6 4 | value: abcdef 5 | length: 9 6 | value: abcdefghi 7 | b 8 | c 9 | d 10 | e 11 | f 12 | -------------------------------------------------------------------------------- /tests/functional/std/sys/dir.kit: -------------------------------------------------------------------------------- 1 | import kit.sys.dir; 2 | 3 | function main() { 4 | var path = "tests/functional/std/sys/"; 5 | for dir in Directory.read(path) { 6 | var path = (*dir).path; 7 | if path == "dir.kit" { 8 | printf("found dir.kit\n"); 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /tests/functional/std/sys/dir.stdout: -------------------------------------------------------------------------------- 1 | found dir.kit 2 | -------------------------------------------------------------------------------- /tests/functional/std/sys/file.kit: -------------------------------------------------------------------------------- 1 | import kit.sys.file; 2 | 3 | function main() { 4 | var fWrite: File = File.write("test_file"); 5 | var writer: Box[Writer] = fWrite; 6 | writer.write("hello"); 7 | fWrite.close(); 8 | 9 | if !File.exists("test_file") { 10 | printf("test_file should exist\n"); 11 | } 12 | 13 | var fWrite2: File = File.write("test_file"); 14 | fWrite2.writeBytes("hi ", 3); 15 | fWrite2.close(); 16 | 17 | var fAppend: File = File.append("test_file"); 18 | fAppend.writeBytes("there", 6); 19 | fAppend.close(); 20 | 21 | var fUpdate: File = File.update("test_file"); 22 | fUpdate.writeBytes("hey", 3); 23 | printf("size after update: %zu\n", fUpdate.getSize()); 24 | fUpdate.close(); 25 | 26 | var fRead: File = File.read("test_file"); 27 | var reader: Box[Reader] = fRead; 28 | var s: Ptr[Void] = malloc(9); 29 | reader.readBytes(s, 8); 30 | (s as CString)[8] = 0; 31 | printf("%s\n", s as CString); 32 | printf("final size: %zu\n", fRead.getSize()); 33 | fRead.close(); 34 | 35 | var removed = File.remove("test_file"); 36 | if !removed { 37 | printf("test_file should have been removed\n"); 38 | } 39 | if File.exists("test_file") { 40 | printf("test_file should have been removed\n"); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /tests/functional/std/sys/file.stdout: -------------------------------------------------------------------------------- 1 | size after update: 9 2 | heythere 3 | final size: 9 4 | -------------------------------------------------------------------------------- /tests/functional/std/sys/path.kit: -------------------------------------------------------------------------------- 1 | import kit.sys.path; 2 | 3 | function main() { 4 | var path1: Path = "/path/to/something"; 5 | var path2: Path = "something_else"; 6 | printf("%s\n", path1.join(path2)); 7 | 8 | var path3: Path = "/path/to/something/"; 9 | printf("%s\n", path3.join(path2)); 10 | 11 | printf(if path1.isAbsolute() then "abs\n" else "not abs\n"); 12 | printf(if path2.isAbsolute() then "abs\n" else "not abs\n"); 13 | printf(if path3.isAbsolute() then "abs\n" else "not abs\n"); 14 | } 15 | -------------------------------------------------------------------------------- /tests/functional/std/sys/utils.kit: -------------------------------------------------------------------------------- 1 | import kit.sys.utils; 2 | 3 | function main() { 4 | sleep(0.000001); 5 | var t = time(); 6 | printf("%.2f\n", t); 7 | } 8 | -------------------------------------------------------------------------------- /tests/functional/std/vector.kit: -------------------------------------------------------------------------------- 1 | function gt3(i: Ptr[Int]) { 2 | return *i > 3; 3 | } 4 | 5 | function main() { 6 | var v: Vector[Int] = Vector.new(4); 7 | printf("length = %zu\n", v.length); 8 | printf("capacity = %zu\n", v.data.length); 9 | 10 | v.push(1); 11 | printf("length = %zu\n", v.length); 12 | printf("capacity = %zu\n", v.data.length); 13 | printf(if v.pop().isSome() then "some\n" else "none\n"); 14 | printf("length = %zu\n", v.length); 15 | printf("capacity = %zu\n", v.data.length); 16 | printf(if v.pop().isSome() then "some\n" else "none\n"); 17 | printf("length = %zu\n", v.length); 18 | printf("capacity = %zu\n", v.data.length); 19 | 20 | v.push(11); 21 | v.push(22); 22 | v.push(33); 23 | v.push(44); 24 | printf("length = %zu\n", v.length); 25 | printf("capacity = %zu\n", v.data.length); 26 | 27 | for i in v { 28 | printf("iterate: %i\n", i); 29 | } 30 | 31 | v.push(55); 32 | printf("length = %zu\n", v.length); 33 | printf("capacity = %zu\n", v.data.length); 34 | 35 | v.push(66); 36 | v.push(77); 37 | printf("length = %zu\n", v.length); 38 | printf("capacity = %zu\n", v.data.length); 39 | 40 | for i in v { 41 | printf("iterate: %i\n", i); 42 | } 43 | 44 | v.pop(); 45 | v.pop(); 46 | v.pop(); 47 | 48 | printf("length = %zu\n", v.length); 49 | printf("capacity = %zu\n", v.data.length); 50 | 51 | for i in v { 52 | printf("iterate: %i\n", i); 53 | } 54 | 55 | printf("length = %zu\n", v.length); 56 | v.clear(); 57 | printf("length after clear = %zu\n", v.length); 58 | 59 | v.free(); 60 | 61 | var v2: Vector[Int] = Vector.new(); 62 | 63 | { 64 | var v1: Vector[Int] = Vector.new(3); 65 | v1.push(1); 66 | v1.push(3); 67 | v1.push(5); 68 | 69 | var v2: Vector[Int] = Vector.new(3); 70 | v2.push(5); 71 | v2.push(6); 72 | v2.push(7); 73 | 74 | var v3: Vector[Int] = Vector.new(3); 75 | v3.push(0); 76 | v3.push(1); 77 | v3.push(2); 78 | 79 | for v in [v1, v2, v3] { 80 | puts(if v.any(gt3) then "any = true" else "any = false"); 81 | puts(if v.all(gt3) then "all = true" else "all = false"); 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /tests/functional/std/vector.stdout: -------------------------------------------------------------------------------- 1 | length = 0 2 | capacity = 4 3 | length = 1 4 | capacity = 4 5 | some 6 | length = 0 7 | capacity = 4 8 | none 9 | length = 0 10 | capacity = 4 11 | length = 4 12 | capacity = 4 13 | iterate: 11 14 | iterate: 22 15 | iterate: 33 16 | iterate: 44 17 | length = 5 18 | capacity = 6 19 | length = 7 20 | capacity = 9 21 | iterate: 11 22 | iterate: 22 23 | iterate: 33 24 | iterate: 44 25 | iterate: 55 26 | iterate: 66 27 | iterate: 77 28 | length = 4 29 | capacity = 9 30 | iterate: 11 31 | iterate: 22 32 | iterate: 33 33 | iterate: 44 34 | length = 4 35 | length after clear = 0 36 | any = true 37 | all = false 38 | any = true 39 | all = true 40 | any = false 41 | all = false 42 | -------------------------------------------------------------------------------- /tests/functional/std/yaml.stdout: -------------------------------------------------------------------------------- 1 | str_key: hello! 2 | bool_key: true 3 | int_key: 1 4 | null_key: null 5 | nested_key1: 6 | nested_array: 7 | - 1 8 | - 2 9 | array_key: 10 | - 2 11 | - false 12 | - null 13 | nested_key2: 14 | child_key: 4 15 | array_of_objects: 16 | - 17 | name: first_object 18 | value: 1 19 | - 20 | name: second_object 21 | value: 2 22 | hello! 23 | child_key: 4 24 | no nested_key3 25 | 4 26 | false 27 | 2 28 | false 29 | null 30 | -------------------------------------------------------------------------------- /tests/functional/structs.kit: -------------------------------------------------------------------------------- 1 | struct MyStruct { 2 | public static var xyz = "hi"; 3 | 4 | var a: Int = 1; 5 | var b: CString = "hello"; 6 | var c = 5; 7 | var d: Bool = undefined; 8 | var e: Ptr[Float]; 9 | } 10 | 11 | struct MyStruct2 { 12 | var a: MyStruct; 13 | } 14 | 15 | struct MyStruct3 { 16 | var a: MyStruct2; 17 | var b: Ptr[MyStruct]; 18 | } 19 | 20 | function main() { 21 | var f = 5_f32; 22 | var a = struct MyStruct { 23 | c: 6, 24 | d: true, 25 | e: f, 26 | }; 27 | // autorefderef of struct pointer field 28 | var g: Float = a.e; 29 | printf("%.1f\n", g); 30 | 31 | printf("%s\n", MyStruct.xyz); 32 | printf("%s\n", a.b); 33 | 34 | var b: Ptr[MyStruct] = &a; 35 | var y = b.a; 36 | 37 | var s2 = struct MyStruct2 {a}; 38 | var s3 = struct MyStruct3 {a: s2, b: a}; 39 | 40 | puts("MyStruct fields:"); 41 | for field in MyStruct.fields { 42 | printf("- "); 43 | puts(field); 44 | } 45 | 46 | // reassign with default values 47 | printf("%i %s\n", a.c, if a.d then "true" else "false"); 48 | a = struct MyStruct {d: false}; 49 | printf("%i %s\n", a.c, if a.d then "true" else "false"); 50 | } 51 | -------------------------------------------------------------------------------- /tests/functional/structs.stdout: -------------------------------------------------------------------------------- 1 | 5.0 2 | hi 3 | hello 4 | MyStruct fields: 5 | - a 6 | - b 7 | - c 8 | - d 9 | - e 10 | 6 true 11 | 5 false 12 | -------------------------------------------------------------------------------- /tests/functional/test1/_mod1.kit: -------------------------------------------------------------------------------- 1 | function f() { 2 | printf("hello"); 3 | } 4 | -------------------------------------------------------------------------------- /tests/functional/test1/test2/_mod2.kit: -------------------------------------------------------------------------------- 1 | function g() { 2 | puts(" world!"); 3 | } 4 | -------------------------------------------------------------------------------- /tests/functional/test_header1.h: -------------------------------------------------------------------------------- 1 | typedef enum { 2 | Var1, 3 | Var2, 4 | Var3, 5 | } TestEnum; 6 | 7 | void myUnimplementedFunction(); 8 | -------------------------------------------------------------------------------- /tests/functional/traits.kit: -------------------------------------------------------------------------------- 1 | trait TestTrait { 2 | static var staticVar: CString; 3 | static function staticMethod(): Void; 4 | function a(): Void; 5 | function b(a: Int): Int; 6 | } 7 | 8 | implement TestTrait for Int { 9 | static var staticVar: CString; 10 | 11 | public static function staticMethod() { 12 | printf("Int.TestTrait.staticMethod()"); 13 | } 14 | 15 | public function a() { 16 | printf("Int's TestTrait method a\n"); 17 | } 18 | 19 | public function b(x: Int) { 20 | printf("Int's TestTrait method b\n"); 21 | return this + x; 22 | } 23 | } 24 | 25 | 26 | implement TestTrait for CString { 27 | public static var staticVar: CString; 28 | 29 | public static function staticMethod() { 30 | printf("CString.TestTrait.staticMethod(): %s\n", Self.TestTrait.staticVar); 31 | } 32 | 33 | public function a() { 34 | printf("CString %s's TestTrait method a\n", this); 35 | } 36 | 37 | public function b(x: Int) { 38 | printf("CString %s's TestTrait method b\n", this); 39 | return x; 40 | } 41 | } 42 | 43 | function main() { 44 | // static trait dispatch 45 | (1_i).TestTrait.a(); 46 | printf("%i\n", (1_i).TestTrait.b(2)); 47 | 48 | var s: CString = "hello"; 49 | s.TestTrait.a(); 50 | printf("%i\n", s.TestTrait.b(3)); 51 | 52 | var x: Int = 777; 53 | var p: Ptr[Int] = &x; 54 | p.TestTrait.a(); 55 | printf("%i\n", p.TestTrait.b(5)); 56 | 57 | // call trait static method 58 | CString.TestTrait.staticVar = "hello"; 59 | CString.TestTrait.staticMethod(); 60 | // CString.TestTrait.a("hi"); 61 | } 62 | -------------------------------------------------------------------------------- /tests/functional/traits.stdout: -------------------------------------------------------------------------------- 1 | Int's TestTrait method a 2 | Int's TestTrait method b 3 | 3 4 | CString hello's TestTrait method a 5 | CString hello's TestTrait method b 6 | 3 7 | Int's TestTrait method a 8 | Int's TestTrait method b 9 | 782 10 | CString.TestTrait.staticMethod(): hello 11 | -------------------------------------------------------------------------------- /tests/functional/tuples.kit: -------------------------------------------------------------------------------- 1 | rules TupleMath { 2 | // add tuples componentwise 3 | (${a: (Int, Int)} + ${n: (Int, Int)}) => ($a[0] + $n[0], $a[1] + $n[1]); 4 | } 5 | 6 | function main() { 7 | var x: (Int, CString, CString) = (1, "second value", "third value"); 8 | var y: (CString, Int) = ("something", 2); 9 | var z: (CString, Int) = ("something", 2); 10 | 11 | var a: Int; 12 | var b: CString; 13 | (a, b, _) = x; 14 | printf("%i\n", a); 15 | printf("%s\n", b); 16 | printf("%s\n", x[2]); 17 | 18 | var c: CString; 19 | var d: Int; 20 | (c, d) = ("something", 3); 21 | printf("%s\n", c); 22 | printf("%i\n", d); 23 | 24 | var e = (1, ("inner slot 1", "inner slot 2")); 25 | var f: Int; 26 | var g: CString; 27 | var h: CString; 28 | (f, (g, h)) = e; 29 | printf("%i\n", f); 30 | printf("%s\n", g); 31 | printf("%s\n", h); 32 | 33 | // let's go nuts here 34 | var i: (Int, (Int, (Int, Int), (Int, Int, Int), (Int, (Int, Int), (Int, Int)))) = (1, (1, (1, 1), (1, 1, 2), (1, (1, 1), (1, 1)))); 35 | var j: Int; 36 | (_, (_, (_, _), (_, _, j), (_, (_, _), (_, _)))) = i; 37 | printf("%i\n", j); 38 | printf("%i\n", i[1][2][2]); 39 | 40 | var a2: (Int, Float, CString) = (1, 2, "hello!"); 41 | var b2: Int; 42 | (b2, _, _) = a2; 43 | printf("%.2f\n", a2[1]); 44 | 45 | using rules TupleMath { 46 | var a = (1_i, 2_i) + (3_i, 4_i); 47 | printf("(%i, %i)\n", a[0], a[1]); 48 | } 49 | 50 | // this could probably be cleaned up by supporting tuples in autorefderef 51 | var d2 = (2, "hello"); 52 | var c2: (Int, Ptr[(Int, CString)]) = (1, &d2); 53 | printf("%s\n", (*c2[1])[1]); 54 | 55 | // TODO: tuple equality 56 | } 57 | -------------------------------------------------------------------------------- /tests/functional/tuples.stdout: -------------------------------------------------------------------------------- 1 | 1 2 | second value 3 | third value 4 | something 5 | 3 6 | 1 7 | inner slot 1 8 | inner slot 2 9 | 2 10 | 2 11 | 2.00 12 | (4, 6) 13 | hello 14 | -------------------------------------------------------------------------------- /tests/functional/type_exprs.kit: -------------------------------------------------------------------------------- 1 | function main() { 2 | var m1 = Map[Int, Float].new(1); 3 | var m2 = Map[Int, Map[Int, Int]].new(1); 4 | var m3 = Map[Int, (Int, Float)].new(1); 5 | var m4 = Map[Int, (Int, Map[Int, Int])].new(1); 6 | var m5 = Map[Int, (Int, Shared[Int])].new(1); 7 | 8 | m1.put(1, 1.0); 9 | m2.put(2, Map[Int, Int].new(1)); 10 | m3.put(3, (1, 2.0)); 11 | m4.put(4, (3, Map[Int, Int].new(1))); 12 | m5.put(5, (1, Shared.alloc(1))); 13 | 14 | printf("%zu\n", m1.length); 15 | printf("%zu\n", m2.length); 16 | printf("%zu\n", m3.length); 17 | printf("%zu\n", m4.length); 18 | printf("%zu\n", m5.length); 19 | } 20 | -------------------------------------------------------------------------------- /tests/functional/type_exprs.stdout: -------------------------------------------------------------------------------- 1 | 1 2 | 1 3 | 1 4 | 1 5 | 1 6 | -------------------------------------------------------------------------------- /tests/functional/typedef.kit: -------------------------------------------------------------------------------- 1 | struct MyStruct { 2 | public static function staticMethod() { 3 | puts("MyStruct.staticMethod()"); 4 | } 5 | 6 | public var a: Int; 7 | public var b: Int; 8 | 9 | public function instanceMethod() { 10 | puts("MyStruct.instanceMethod()"); 11 | } 12 | } 13 | 14 | typedef MyTypedef = MyStruct; 15 | 16 | struct MyGenericStruct[$N] { 17 | public static function getLength(): Int { 18 | return N; 19 | } 20 | 21 | var arr: CArray[Int, N] = empty; 22 | } 23 | 24 | typedef GenStruct4 = MyGenericStruct[4]; 25 | typedef GenStruct8 = MyGenericStruct[8]; 26 | 27 | function main() { 28 | MyTypedef.staticMethod(); 29 | var x: MyTypedef = struct MyTypedef {a: 1, b: 2}; 30 | x.instanceMethod(); 31 | var y: MyStruct = struct MyStruct{a: 3, b: 4}; 32 | var z = y as MyTypedef; 33 | 34 | var genStruct4 = struct GenStruct4; 35 | var genStruct8 = struct GenStruct8; 36 | printf("%i\n", GenStruct4.getLength()); 37 | printf("%i\n", GenStruct8.getLength()); 38 | } 39 | -------------------------------------------------------------------------------- /tests/functional/typedef.stdout: -------------------------------------------------------------------------------- 1 | MyStruct.staticMethod() 2 | MyStruct.instanceMethod() 3 | 4 4 | 8 5 | -------------------------------------------------------------------------------- /tests/functional/typeinference.kit: -------------------------------------------------------------------------------- 1 | function voidFunc1() { 2 | return; 3 | } 4 | function voidFunc2() { 5 | printf("hello!\n"); 6 | } 7 | function voidFunc3() {} 8 | function voidFunc4(): Void {} 9 | 10 | function numFunc1() { 11 | return 1; 12 | } 13 | 14 | function numFunc2(): _ { 15 | return 1 + 2; 16 | } 17 | 18 | function numFunc3(): Float { 19 | return numFunc1(); 20 | } 21 | 22 | function main() { 23 | voidFunc1(); 24 | voidFunc2(); 25 | voidFunc3(); 26 | voidFunc4(); 27 | var a = numFunc1(); 28 | var b = numFunc2(); 29 | var c = numFunc3(); 30 | var d: _ = numFunc2(); 31 | 32 | printf("%.2f\n", a + b + c + d); 33 | } 34 | -------------------------------------------------------------------------------- /tests/functional/typeinference.stdout: -------------------------------------------------------------------------------- 1 | hello! 2 | 8.00 3 | -------------------------------------------------------------------------------- /tests/functional/unions.kit: -------------------------------------------------------------------------------- 1 | union MyUnion { 2 | public static var xyz = "hi"; 3 | 4 | var a: Char; 5 | var b: CString; 6 | } 7 | 8 | function main() { 9 | printf("%s\n", MyUnion.xyz); 10 | var a: MyUnion; 11 | a.a = 100; 12 | printf("%hhi\n", a.a); 13 | a.b = "abcdefg"; 14 | printf("%s\n", a.b); 15 | 16 | puts("MyUnion fields:"); 17 | for field in MyUnion.fields { 18 | printf("- "); 19 | puts(field); 20 | } 21 | 22 | var x = union MyUnion {a: c'a'}; 23 | var y = union MyUnion {b: "hello"}; 24 | } 25 | -------------------------------------------------------------------------------- /tests/functional/unions.stdout: -------------------------------------------------------------------------------- 1 | hi 2 | 100 3 | abcdefg 4 | MyUnion fields: 5 | - a 6 | - b 7 | -------------------------------------------------------------------------------- /tests/functional/varargs.kit: -------------------------------------------------------------------------------- 1 | include "stdarg.h"; 2 | 3 | function f(num: Int, b...) { 4 | printf("args: %i\n", num); 5 | for i in 0 ... num { 6 | var x: Int = b; 7 | printf("%i\n", x); 8 | } 9 | } 10 | 11 | function g(num: Int, args...) { 12 | vf(num, (args...)); 13 | } 14 | 15 | function vf(num: Int, args: va_list) { 16 | printf("args: %i\n", num); 17 | } 18 | 19 | function main() { 20 | f(3, 1, 2, 3); 21 | f(5, 4, 5, 6, 7, 8); 22 | g(2, 1, 2); 23 | } 24 | -------------------------------------------------------------------------------- /tests/functional/varargs.stdout: -------------------------------------------------------------------------------- 1 | args: 3 2 | 1 3 | 2 4 | 3 5 | args: 5 6 | 4 7 | 5 8 | 6 9 | 7 10 | 8 11 | args: 2 12 | -------------------------------------------------------------------------------- /tests/functional/while.kit: -------------------------------------------------------------------------------- 1 | function main() { 2 | var a = 1; 3 | while (a < 5) { 4 | printf("%i\n", a); 5 | a++; 6 | } 7 | 8 | var b = 1; 9 | while (true) { 10 | if b == 2 { 11 | ++b; 12 | continue; 13 | } 14 | printf("%i\n", b); 15 | if ++b == 4 { 16 | break; 17 | } 18 | } 19 | 20 | var c = 3; 21 | do { 22 | printf("at least once\n"); 23 | } while (c < 3); 24 | } 25 | -------------------------------------------------------------------------------- /tests/functional/while.stdout: -------------------------------------------------------------------------------- 1 | 1 2 | 2 3 | 3 4 | 4 5 | 1 6 | 3 7 | at least once 8 | -------------------------------------------------------------------------------- /toolchains/darwin-clang: -------------------------------------------------------------------------------- 1 | CC=clang 2 | CPPFLAGS="-U__BLOCKS__" 3 | CFLAGS="-std=c99 -pedantic -O3 -Os -Wno-unused-command-line-argument -Wno-shift-op-parentheses -Wno-expansion-to-defined -Wno-gnu-zero-variadic-macro-arguments" 4 | -------------------------------------------------------------------------------- /toolchains/darwin-gcc: -------------------------------------------------------------------------------- 1 | CC=gcc 2 | CPPFLAGS="-U__BLOCKS__" 3 | CFLAGS="-std=c99 -pedantic -O3 -Os -Wno-unused-command-line-argument -Wno-missing-braces -Wno-shift-op-parentheses -Wno-expansion-to-defined -Wno-gnu-zero-variadic-macro-arguments" 4 | -------------------------------------------------------------------------------- /toolchains/emscripten: -------------------------------------------------------------------------------- 1 | CC=emcc 2 | CFLAGS="-pedantic -Wno-missing-braces -Wno-shift-op-parentheses -U__cplusplus" 3 | KITFLAGS="--no-ccache --single-pass" 4 | -------------------------------------------------------------------------------- /toolchains/linux-clang: -------------------------------------------------------------------------------- 1 | CC=clang 2 | CFLAGS="-std=c99 -pedantic -O3 -Os -Wno-unused-command-line-argument -Wno-shift-op-parentheses" 3 | -------------------------------------------------------------------------------- /toolchains/linux-gcc: -------------------------------------------------------------------------------- 1 | CC=gcc 2 | CFLAGS="-std=c99 -pedantic -O3 -Os -Wno-missing-braces -Wno-shift-op-parentheses" 3 | -------------------------------------------------------------------------------- /toolchains/none: -------------------------------------------------------------------------------- 1 | CC=echo 2 | CFLAGS="this toolchain is disabled" 3 | KITFLAGS="--no-ccache --single-pass" 4 | -------------------------------------------------------------------------------- /toolchains/windows-mingw: -------------------------------------------------------------------------------- 1 | CC=gcc 2 | CPPFLAGS="-D__USE_MINGW_ANSI_STDIO" 3 | CFLAGS="-std=c99 -pedantic -O3 -Os -Wno-missing-braces -Wno-shift-op-parentheses" 4 | -------------------------------------------------------------------------------- /utils/kit.kak: -------------------------------------------------------------------------------- 1 | # http://www.kitlang.org 2 | # ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾ 3 | 4 | # Detection 5 | # ‾‾‾‾‾‾‾‾‾ 6 | 7 | hook global BufCreate .*\.(kit) %{ 8 | set-option buffer filetype kit 9 | } 10 | 11 | # Highlighters 12 | # ‾‾‾‾‾‾‾‾‾‾‾‾ 13 | 14 | add-highlighter shared/kit regions 15 | add-highlighter shared/kit/code default-region group 16 | add-highlighter shared/kit/string region '"' (?" 4 | color brightgreen "\<(struct|enum|union|abstract|function|implement|specialize|trait|typedef|var|private|public|static|const|inline|using)\>" 5 | color brightred "\<(return|throw|for|as|in|if|then|else|do|while|match|default|unsafe|rule|rules|implicit|sizeof)\>" 6 | color brightred "=>" 7 | color brightcyan "\<[A-Z][a-zA-Z0-9_]*\>" 8 | color brightyellow ""[^"]*"" 9 | color brightyellow "'[^']*'" 10 | color brightblack "//.*" 11 | color brightblack start="/\*" end="\*/" 12 | color magenta "(true|false|null)" 13 | -------------------------------------------------------------------------------- /utils/vscode-kitlang/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | *.vsix -------------------------------------------------------------------------------- /utils/vscode-kitlang/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | // A launch configuration that launches the extension inside a new window 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | { 6 | "version": "0.2.0", 7 | "configurations": [ 8 | { 9 | "name": "Extension", 10 | "type": "extensionHost", 11 | "request": "launch", 12 | "runtimeExecutable": "${execPath}", 13 | "args": [ 14 | "--extensionDevelopmentPath=${workspaceFolder}" 15 | ] 16 | } 17 | ] 18 | } -------------------------------------------------------------------------------- /utils/vscode-kitlang/.vscodeignore: -------------------------------------------------------------------------------- 1 | .vscode/** 2 | .vscode-test/** 3 | .gitignore 4 | vsc-extension-quickstart.md 5 | -------------------------------------------------------------------------------- /utils/vscode-kitlang/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | All notable changes to the "kitlang" extension will be documented in this file. 3 | 4 | Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how to structure this file. 5 | 6 | ## [Unreleased] 7 | - Initial release -------------------------------------------------------------------------------- /utils/vscode-kitlang/README.md: -------------------------------------------------------------------------------- 1 | # Kit language support for Visual Studio Code 2 | 3 | This is the official Visual Studio Code extension for Kit. 4 | 5 | ## Features 6 | 7 | - Syntax highlighting 8 | 9 | ## Planned Features 10 | 11 | - Language server implementation 12 | -------------------------------------------------------------------------------- /utils/vscode-kitlang/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kitlang/kit/2769a7a8e51fe4466c50439d1a1ebdad0fb79710/utils/vscode-kitlang/icon.png -------------------------------------------------------------------------------- /utils/vscode-kitlang/language-configuration.json: -------------------------------------------------------------------------------- 1 | { 2 | "comments": { 3 | // symbol used for single line comment. Remove this entry if your language does not support line comments 4 | "lineComment": "//", 5 | // symbols used for start and end a block comment. Remove this entry if your language does not support block comments 6 | "blockComment": [ "/*", "*/" ] 7 | }, 8 | // symbols used as brackets 9 | "brackets": [ 10 | ["{", "}"], 11 | ["[", "]"], 12 | ["(", ")"] 13 | ], 14 | // symbols that are auto closed when typing 15 | "autoClosingPairs": [ 16 | ["{", "}"], 17 | ["[", "]"], 18 | ["(", ")"], 19 | ["\"", "\""], 20 | ["'", "'"] 21 | ], 22 | // symbols that that can be used to surround a selection 23 | "surroundingPairs": [ 24 | ["{", "}"], 25 | ["[", "]"], 26 | ["(", ")"], 27 | ["\"", "\""], 28 | ["'", "'"] 29 | ] 30 | } -------------------------------------------------------------------------------- /utils/vscode-kitlang/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "kitlang", 3 | "displayName": "Kit", 4 | "description": "Kit programming language support", 5 | "version": "0.0.1", 6 | "publisher": "kitlang", 7 | "icon": "icon.png", 8 | "engines": { 9 | "vscode": "^1.25.0" 10 | }, 11 | "categories": [ 12 | "Programming Languages" 13 | ], 14 | "contributes": { 15 | "languages": [{ 16 | "id": "kit", 17 | "aliases": ["Kit", "kit"], 18 | "extensions": [".kit"], 19 | "configuration": "./language-configuration.json" 20 | }], 21 | "grammars": [{ 22 | "language": "kit", 23 | "scopeName": "source.kit", 24 | "path": "./syntaxes/kit.tmLanguage" 25 | }] 26 | }, 27 | "bugs": { 28 | "url": "https://github.com/kitlang/kit/issues" 29 | }, 30 | "repository": { 31 | "type": "git", 32 | "url": "https://github.com/kitlang/kit.git" 33 | }, 34 | "homepage": "https://www.kitlang.org/" 35 | } 36 | --------------------------------------------------------------------------------