diff --git a/.github/workflows/tests_alpha.yml b/.github/workflows/tests_alpha.yml deleted file mode 100644 index a7bd7336..00000000 --- a/.github/workflows/tests_alpha.yml +++ /dev/null @@ -1,48 +0,0 @@ -on: - pull_request: - workflow_dispatch: - -name: Test examples without nix using alpha release - -# this cancels workflows currently in progress if you start a new one -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true - -# Do not add permissions here! Configure them at the job level! -permissions: {} - -jobs: - test-examples: - runs-on: ${{ matrix.operating-system }} - strategy: - matrix: - operating-system: [ubuntu-22.04, ubuntu-24.04, ubuntu-24.04-arm, macos-15-intel, macos-15] - timeout-minutes: 90 - steps: - - uses: actions/checkout@v4 - - - uses: roc-lang/setup-roc@39c354a6a838a0089eea9068a0414f49b62c5c08 - with: - version: alpha4-rolling - - - name: Run Roc - run: roc version - - - name: Install dependencies (Ubuntu) - if: startsWith(matrix.operating-system, 'ubuntu-') - run: sudo apt install -y expect - - - name: Install dependencies (macOS) - if: startsWith(matrix.operating-system, 'macos-') - run: | - brew install expect - brew install z3 - - - name: check if roc files are properly formatted - run: ROC=roc ./ci_scripts/check_format.sh - - - run: ROC=roc ./ci_scripts/all_tests.sh - - - name: Checks if every folder in examples is mentioned in ./examples/index.md - run: bash ./ci_scripts/check_index.sh diff --git a/.github/workflows/tests_nightly.yml b/.github/workflows/tests_nightly.yml index 23d2ebc3..90e60b0f 100644 --- a/.github/workflows/tests_nightly.yml +++ b/.github/workflows/tests_nightly.yml @@ -17,14 +17,17 @@ jobs: runs-on: ${{ matrix.operating-system }} strategy: matrix: - operating-system: [ubuntu-22.04, ubuntu-24.04, ubuntu-24.04-arm, macos-15-intel, macos-15] + operating-system: [ubuntu-24.04] + # TODO re-enable all operating systems + #operating-system: [ubuntu-22.04, ubuntu-24.04, ubuntu-24.04-arm, macos-15-intel, macos-15, windows-2025, windows-11-arm] timeout-minutes: 90 steps: - uses: actions/checkout@v4 - - uses: roc-lang/setup-roc@39c354a6a838a0089eea9068a0414f49b62c5c08 + - uses: roc-lang/setup-roc@30ff82b396cbeb36a662a18f5c652773efb43e72 with: - version: nightly + # Installs the latest nightly from https://github.com/roc-lang/nightlies + version: nightly-new-compiler - name: Run Roc run: roc version diff --git a/.github/workflows/tests_nix.yml b/.github/workflows/tests_nix.yml deleted file mode 100644 index 90c9cd41..00000000 --- a/.github/workflows/tests_nix.yml +++ /dev/null @@ -1,33 +0,0 @@ -on: - pull_request: - workflow_dispatch: - -name: Test examples on Nix - -# this cancels workflows currently in progress if you start a new one -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true - -# Do not add permissions here! Configure them at the job level! -permissions: {} - -jobs: - test-examples: - runs-on: [ubuntu-22.04] - steps: - - uses: actions/checkout@v4 - - # install nix - - uses: cachix/install-nix-action@02a151ada4993995686f9ed4f1be7cfbb229e56f # commit for v31 - with: - nix_path: nixpkgs=channel:nixos-unstable - - - uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # commit for v16 - with: - name: enigmaticsunrise - authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}' - - # the result folder is produced by the previous step - - name: Run all tests - run: nix develop -c sh -c 'export ROC=roc && ./ci_scripts/all_tests.sh' \ No newline at end of file diff --git a/ci_scripts/all_tests.sh b/ci_scripts/all_tests.sh index e06ea939..f97a6cdc 100755 --- a/ci_scripts/all_tests.sh +++ b/ci_scripts/all_tests.sh @@ -15,119 +15,196 @@ if [ -z "${ROC}" ]; then exit 1 fi -$ROC build ./examples/HelloWorld/main.roc -expect ci_scripts/expect_scripts/HelloWorld.exp +# opt-in list of examples to test (add examples as they are updated for the new compiler) +optin=( + "Tuples" +) + +is_optin() { + local name="$1" + for entry in "${optin[@]}"; do + if [[ "$entry" == "$name" ]]; then + return 0 + fi + done + return 1 +} + +if is_optin "HelloWorld"; then + $ROC build ./examples/HelloWorld/main.roc + expect ci_scripts/expect_scripts/HelloWorld.exp +fi -$ROC build ./examples/FizzBuzz/main.roc -$ROC test ./examples/FizzBuzz/main.roc -expect ci_scripts/expect_scripts/FizzBuzz.exp +if is_optin "FizzBuzz"; then + $ROC build ./examples/FizzBuzz/main.roc + $ROC test ./examples/FizzBuzz/main.roc + expect ci_scripts/expect_scripts/FizzBuzz.exp +fi -$ROC test ./examples/GraphTraversal/Graph.roc +if is_optin "GraphTraversal"; then + $ROC test ./examples/GraphTraversal/Graph.roc +fi -$ROC build ./examples/Json/main.roc --linker=legacy -expect ci_scripts/expect_scripts/Json.exp +if is_optin "Json"; then + $ROC build ./examples/Json/main.roc --linker=legacy + expect ci_scripts/expect_scripts/Json.exp +fi -$ROC build ./examples/LeastSquares/main.roc -expect ci_scripts/expect_scripts/LeastSquares.exp +if is_optin "LeastSquares"; then + $ROC build ./examples/LeastSquares/main.roc + expect ci_scripts/expect_scripts/LeastSquares.exp +fi -$ROC build ./examples/IngestFiles/main.roc -expect ci_scripts/expect_scripts/IngestFiles.exp +if is_optin "IngestFiles"; then + $ROC build ./examples/IngestFiles/main.roc + expect ci_scripts/expect_scripts/IngestFiles.exp +fi -$ROC build ./examples/Parser/main.roc -$ROC test ./examples/Parser/main.roc -expect ci_scripts/expect_scripts/Parser.exp +if is_optin "Parser"; then + $ROC build ./examples/Parser/main.roc + $ROC test ./examples/Parser/main.roc + expect ci_scripts/expect_scripts/Parser.exp +fi -$ROC test ./examples/PatternMatching/PatternMatching.roc +if is_optin "PatternMatching"; then + $ROC test ./examples/PatternMatching/PatternMatching.roc +fi -$ROC build ./examples/AllSyntax/main.roc -expect ci_scripts/expect_scripts/AllSyntax.exp +if is_optin "AllSyntax"; then + $ROC build ./examples/AllSyntax/main.roc + expect ci_scripts/expect_scripts/AllSyntax.exp +fi -$ROC build ./examples/RandomNumbers/main.roc -expect ci_scripts/expect_scripts/RandomNumbers.exp +if is_optin "RandomNumbers"; then + $ROC build ./examples/RandomNumbers/main.roc + expect ci_scripts/expect_scripts/RandomNumbers.exp +fi -$ROC build ./examples/CommandLineArgs/main.roc -expect ci_scripts/expect_scripts/CommandLineArgs.exp +if is_optin "CommandLineArgs"; then + $ROC build ./examples/CommandLineArgs/main.roc + expect ci_scripts/expect_scripts/CommandLineArgs.exp +fi -$ROC build ./examples/Commands/main.roc -expect ci_scripts/expect_scripts/Commands.exp +if is_optin "Commands"; then + $ROC build ./examples/Commands/main.roc + expect ci_scripts/expect_scripts/Commands.exp +fi -$ROC build ./examples/CommandLineArgsFile/main.roc -expect ci_scripts/expect_scripts/CommandLineArgsFile.exp +if is_optin "CommandLineArgsFile"; then + $ROC build ./examples/CommandLineArgsFile/main.roc + expect ci_scripts/expect_scripts/CommandLineArgsFile.exp +fi -$ROC build ./examples/TryOperatorDesugaring/main.roc -$ROC test ./examples/TryOperatorDesugaring/main.roc -expect ci_scripts/expect_scripts/TryOperatorDesugaring.exp +if is_optin "TryOperatorDesugaring"; then + $ROC build ./examples/TryOperatorDesugaring/main.roc + $ROC test ./examples/TryOperatorDesugaring/main.roc + expect ci_scripts/expect_scripts/TryOperatorDesugaring.exp +fi -$ROC build ./examples/Tuples/main.roc -expect ci_scripts/expect_scripts/Tuples.exp +if is_optin "Tuples"; then + expect ci_scripts/expect_scripts/Tuples.exp +fi -$ROC test ./examples/TowersOfHanoi/Hanoi.roc +if is_optin "TowersOfHanoi"; then + $ROC test ./examples/TowersOfHanoi/Hanoi.roc +fi -$ROC test ./examples/ErrorHandlingBasic/ErrorHandlingBasic.roc +if is_optin "ErrorHandlingBasic"; then + $ROC test ./examples/ErrorHandlingBasic/ErrorHandlingBasic.roc +fi -$ROC build ./examples/ErrorHandlingRealWorld/main.roc -expect ci_scripts/expect_scripts/ErrorHandlingRealWorld.exp +if is_optin "ErrorHandlingRealWorld"; then + $ROC build ./examples/ErrorHandlingRealWorld/main.roc + expect ci_scripts/expect_scripts/ErrorHandlingRealWorld.exp +fi -$ROC build ./examples/LoopEffect/main.roc -expect ci_scripts/expect_scripts/LoopEffect.exp +if is_optin "LoopEffect"; then + $ROC build ./examples/LoopEffect/main.roc + expect ci_scripts/expect_scripts/LoopEffect.exp +fi -$ROC build ./examples/Snake/main.roc -$ROC test ./examples/Snake/main.roc -expect ci_scripts/expect_scripts/Snake.exp +if is_optin "Snake"; then + $ROC build ./examples/Snake/main.roc + $ROC test ./examples/Snake/main.roc + expect ci_scripts/expect_scripts/Snake.exp +fi -$ROC test ./examples/RecordBuilder/DateParser.roc +if is_optin "RecordBuilder"; then + $ROC test ./examples/RecordBuilder/DateParser.roc +fi -$ROC test ./examples/BasicDict/BasicDict.roc +if is_optin "BasicDict"; then + $ROC test ./examples/BasicDict/BasicDict.roc +fi -$ROC build ./examples/MultipleRocFiles/main.roc -expect ci_scripts/expect_scripts/MultipleRocFiles.exp +if is_optin "MultipleRocFiles"; then + $ROC build ./examples/MultipleRocFiles/main.roc + expect ci_scripts/expect_scripts/MultipleRocFiles.exp +fi -$ROC build ./examples/ImportFromDirectory/main.roc -expect ci_scripts/expect_scripts/ImportFromDirectory.exp +if is_optin "ImportFromDirectory"; then + $ROC build ./examples/ImportFromDirectory/main.roc + expect ci_scripts/expect_scripts/ImportFromDirectory.exp +fi -$ROC build ./examples/EncodeDecode/main.roc -expect ci_scripts/expect_scripts/EncodeDecode.exp +if is_optin "EncodeDecode"; then + $ROC build ./examples/EncodeDecode/main.roc + expect ci_scripts/expect_scripts/EncodeDecode.exp +fi -$ROC build ./examples/SafeMath/main.roc -$ROC test ./examples/SafeMath/main.roc -expect ci_scripts/expect_scripts/SafeMath.exp +if is_optin "SafeMath"; then + $ROC build ./examples/SafeMath/main.roc + $ROC test ./examples/SafeMath/main.roc + expect ci_scripts/expect_scripts/SafeMath.exp +fi -$ROC build ./examples/HelloWeb/main.roc --linker=legacy -expect ci_scripts/expect_scripts/HelloWeb.exp +if is_optin "HelloWeb"; then + $ROC build ./examples/HelloWeb/main.roc --linker=legacy + expect ci_scripts/expect_scripts/HelloWeb.exp +fi -$ROC build ./examples/ImportPackageFromModule/main.roc -expect ci_scripts/expect_scripts/ImportPackageFromModule.exp +if is_optin "ImportPackageFromModule"; then + $ROC build ./examples/ImportPackageFromModule/main.roc + expect ci_scripts/expect_scripts/ImportPackageFromModule.exp +fi -$ROC test ./examples/CustomInspect/OpaqueTypes.roc +if is_optin "CustomInspect"; then + $ROC test ./examples/CustomInspect/OpaqueTypes.roc +fi -$ROC build ./examples/SortStrings/main.roc -$ROC ./examples/SortStrings/main.roc -expect ci_scripts/expect_scripts/SortStrings.exp +if is_optin "SortStrings"; then + $ROC build ./examples/SortStrings/main.roc + $ROC ./examples/SortStrings/main.roc + expect ci_scripts/expect_scripts/SortStrings.exp +fi # these examples don't work on macos and aarch64 linux yet #225 #226 #231 if [[ "$(uname)" == "Linux" && "$(uname -m)" == "x86_64" ]]; then - $ROC build --lib ./examples/GoPlatform/main.roc --output examples/GoPlatform/platform/libapp.so - go build -C examples/GoPlatform/platform -buildmode=pie -o dynhost - - $ROC preprocess-host ./examples/GoPlatform/platform/dynhost ./examples/GoPlatform/platform/main.roc ./examples/GoPlatform/platform/libapp.so - $ROC build ./examples/GoPlatform/main.roc - - # temporarily allow failure of lsb_release in case it is not installed - set +e - os_info=$(lsb_release -a 2>/dev/null) - set -e - - # Skip Go tests if os is Ubuntu and we're not inside nix. This avoids a segfault on CI. See https://github.com/roc-lang/examples/issues/164 - if echo "$os_info" | grep -q "Ubuntu" && [ -z "${IN_NIX_SHELL}" ]; then - echo "Skipping Go test due to https://github.com/roc-lang/examples/issues/164" - else - echo "Running Go test..." - expect ci_scripts/expect_scripts/GoPlatform.exp + if is_optin "GoPlatform"; then + $ROC build --lib ./examples/GoPlatform/main.roc --output examples/GoPlatform/platform/libapp.so + go build -C examples/GoPlatform/platform -buildmode=pie -o dynhost + + $ROC preprocess-host ./examples/GoPlatform/platform/dynhost ./examples/GoPlatform/platform/main.roc ./examples/GoPlatform/platform/libapp.so + $ROC build ./examples/GoPlatform/main.roc + + # temporarily allow failure of lsb_release in case it is not installed + set +e + os_info=$(lsb_release -a 2>/dev/null) + set -e + + # Skip Go tests if os is Ubuntu and we're not inside nix. This avoids a segfault on CI. See https://github.com/roc-lang/examples/issues/164 + if echo "$os_info" | grep -q "Ubuntu" && [ -z "${IN_NIX_SHELL}" ]; then + echo "Skipping Go test due to https://github.com/roc-lang/examples/issues/164" + else + echo "Running Go test..." + expect ci_scripts/expect_scripts/GoPlatform.exp + fi fi - - $ROC build ./examples/DotNetPlatform/main.roc --lib --output ./examples/DotNetPlatform/platform/interop - expect ci_scripts/expect_scripts/DotNetPlatform.exp + if is_optin "DotNetPlatform"; then + $ROC build ./examples/DotNetPlatform/main.roc --lib --output ./examples/DotNetPlatform/platform/interop + expect ci_scripts/expect_scripts/DotNetPlatform.exp + fi fi echo "All tests passed!" diff --git a/ci_scripts/check_format.sh b/ci_scripts/check_format.sh index 55b1560f..bcfa2558 100755 --- a/ci_scripts/check_format.sh +++ b/ci_scripts/check_format.sh @@ -16,18 +16,12 @@ if [ -z "${ROC}" ]; then exit 1 fi -# array of paths to exclude from format check -# AllSyntax: The formatter changes `||`` into `or`, and we want to demonstrate both in the example -excludes=( './examples/AllSyntax/main.roc' './roc_nightly/' ) +# opt-in list of files to format check (add files as they are updated for the new compiler) +optin=( + "examples/Tuples/main.roc" +) -# Start the find command and loop through excludes to add them -find_command="find . -name '*.roc'" -for exclude in "${excludes[@]}"; do - find_command+=" ! -path '$exclude*'" -done - -# `roc format --check`` all roc files -for file in $(eval "$find_command"); do - echo "Checking if $file was formatted with roc format..." - $ROC format --check "$file" +for file in "${optin[@]}"; do + echo "Checking if $file was formatted with roc fmt..." + $ROC fmt --check "$file" done diff --git a/ci_scripts/expect_scripts/Tuples.exp b/ci_scripts/expect_scripts/Tuples.exp index 5083b93c..f4ea5e5c 100644 --- a/ci_scripts/expect_scripts/Tuples.exp +++ b/ci_scripts/expect_scripts/Tuples.exp @@ -7,9 +7,9 @@ set timeout 7 source ./ci_scripts/expect_scripts/shared-code.exp -spawn ./examples/Tuples/main +spawn $env(ROC) ./examples/Tuples/main.roc --no-cache -expect "First is: A String,\r\nSecond is: true,\r\nThird is: 15000000.\r\nYou also have some pears.\r\n" { +expect "First is: Just a String,\r\nSecond is: true,\r\nThird is: 15000000.0.\r\n\r\nYou have some pears.\r\n" { expect eof { check_exit_and_segfault } diff --git a/examples/Tuples/README.md b/examples/Tuples/README.md index 077d6123..03181f14 100644 --- a/examples/Tuples/README.md +++ b/examples/Tuples/README.md @@ -5,8 +5,8 @@ For example, instead of having `foo.name` to access the `name` field of a record you might write `foo.0` to access the first field in a tuple (or `foo.1` for the second field, etc.) - ## Code + ```roc file:main.roc ``` @@ -17,8 +17,9 @@ Run this from the directory that has `main.roc` in it: ``` $ roc main.roc -First is: A String, +First is: Just a String, Second is: true, -Third is: 15000000. +Third is: 15000000.0. + You also have some pears. ``` diff --git a/examples/Tuples/main.roc b/examples/Tuples/main.roc index 657a6d8a..f9aee6a0 100644 --- a/examples/Tuples/main.roc +++ b/examples/Tuples/main.roc @@ -1,37 +1,38 @@ -app [main!] { pf: platform "https://github.com/roc-lang/basic-cli/releases/download/0.20.0/X73hGh05nNTkDHU06FHC0YfFaQB1pimX7gncRcao5mU.tar.br" } - -import pf.Stdout -import pf.Arg exposing [Arg] - -main! : List Arg => Result {} _ -main! = |_args| - - # a tuple that contains three different types - simple_tuple : (Str, Bool, I64) - simple_tuple = ("A String", Bool.true, 15_000_000) - - # access the items in a tuple by index (starts at 0) - first_item = simple_tuple.0 - second_item = if simple_tuple.1 then "true" else "false" - third_item = Num.to_str(simple_tuple.2) - - Stdout.line!( - """ - First is: ${first_item}, - Second is: ${second_item}, - Third is: ${third_item}. - """, - )? - - # You can also use tuples with `when`: - fruit_selection : [Apple, Pear, Banana] - fruit_selection = Pear - - quantity = 12 - - when (fruit_selection, quantity) is - # TODO re-enable when github.com/roc-lang/roc/issues/5530 is fixed. - # (_, qty) if qty == 0 -> Stdout.line! "You have no fruit." - (Apple, _) -> Stdout.line!("You also have some apples.") - (Pear, _) -> Stdout.line!("You also have some pears.") - (Banana, _) -> Stdout.line!("You also have some bananas.") +main! : List(Str) => Try({}, _) +main! = |_args| { + + # A tuple that contains three different types + simple_tuple : (Str, Bool, Dec) + simple_tuple = ("Just a String", True, 15_000_000) + + # Access the items in a tuple by index (starts at 0) + first_item = simple_tuple.0 + second_item = if simple_tuple.1 "true" else "false" + third_item = simple_tuple.2.to_str() + + echo!( + \\First is: ${first_item}, + \\Second is: ${second_item}, + \\Third is: ${third_item}. + \\ + , + ) + + # You can also use tuples with `match`: + fruit_selection : [Apple, Pear, Banana] + fruit_selection = Pear + + quantity = 12 + + # Create a tuple of fruites and quantities, + # So you can match on both of them + match (fruit_selection, quantity) { + (_, 0) => echo!("You have no fruit.") + (Apple, 1) => echo!("You have an apple.") + (Apple, _) => echo!("You have some apples.") + (Pear, _) => echo!("You have some pears.") + (Banana, _) => echo!("You have some bananas.") + } + + Ok({}) +}