Skip to content

V4 #37

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Mar 8, 2024
Merged

V4 #37

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 12 additions & 8 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ on:
pull_request:
branches: [ master ]

env:
ARTIFACT_NAME: "linux-clang-15.zip"
CLANG_VERSION: 15

jobs:
build:
runs-on: ubuntu-latest
Expand All @@ -14,29 +18,29 @@ jobs:
- name: Checkout std
uses: actions/checkout@v2

- uses: robinraju/release-downloader@v1.5
- uses: robinraju/release-downloader@v1.9
with:
latest: true
preRelease: true
repository: ArkScript-lang/Ark
fileName: "linux-clang-11.zip"
fileName: ${{ env.ARTIFACT_NAME }}

- name: Set up files
shell: bash
run: |
unzip linux-clang-11.zip
unzip $ARTIFACT_NAME
chmod u+x arkscript *.so lib/*.arkm
cp lib/*.arkm ./

- name: Update LLVM compilers
shell: bash
run: |
version=11
sudo apt-get install -y clang-${version} lld-${version} libc++-${version}-dev libc++abi-${version}-dev clang-tools-${version}
sudo apt-get install -y clang-${CLANG_VERSION} lld-${CLANG_VERSION} \
libc++-${CLANG_VERSION}-dev libc++abi-${CLANG_VERSION}-dev \
clang-tools-${CLANG_VERSION}

- name: Tests
shell: bash
run: |
./arkscript --version
for f in tests/*.ark; do
./arkscript $f -L ./
done
./arkscript tests/all.ark -L ./
2 changes: 1 addition & 1 deletion Events.ark
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
(import "List.ark")
(import std.List)

# @brief Allows to register events listeners and emit events
# =begin
Expand Down
10 changes: 5 additions & 5 deletions List.ark
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
# @param _func the function to call on each element
# @details The original list is left unmodified.
# =begin
# (import "List.ark")
# (import std.List)
# (let collection [1 2 5 12])
# (list:forEach collection (fun (element) {
# (print element)
Expand All @@ -21,7 +21,7 @@
# @param _L the list to iterate over
# @details The original list is left unmodified.
# =begin
# (import "List.ark")
# (import std.List)
# (let collection [1 2 5 12])
# (let p (list:product collection)) # => 120
# =end
Expand All @@ -38,7 +38,7 @@
# @param _L the list to iterate over
# @details The original list is left unmodified.
# =begin
# (import "List.ark")
# (import std.List)
# (let collection [1 2 5 12])
# (let p (list:sum collection)) # => 20
# =end
Expand All @@ -51,7 +51,7 @@
(set _index (+ 1 _index))})
_output }))

(import "Math.ark") # needed for math:min, math:max
(import std.Math :min :max)

# @brief Drop the first n elements of a list
# @param _L the list to work on
Expand Down Expand Up @@ -101,7 +101,7 @@
# @param _f the predicate
# @details The original list is left unmodified.
# =begin
# (import "Math.ark")
# (import std.Math)
# (print (list:filter [1 2 3 4 5 6 7 8 9] math:even)) # [2 4 6 8]
# =end
# @author https://github.com/rstefanic
Expand Down
20 changes: 10 additions & 10 deletions Macros.ark
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
!{-> (arg fn1 ...fn) {
!{if (> (len fn) 0)
($ -> (arg fn1 ...fn) {
($if (> (len fn) 0)
(-> (fn1 arg) ...fn)
(fn1 arg)}}}
(fn1 arg))})

# internal, do not use
!{__suffix-dup (sym x) {
!{if (> x 1)
(__suffix-dup sym (- x 1))}
(symcat sym x)}}
($ __suffix-dup (sym x) {
($if (> x 1)
(__suffix-dup sym (- x 1)))
(symcat sym x)})

!{partial (func ...defargs) {
!{bloc (__suffix-dup a (- (argcount func) (len defargs)))}
($ partial (func ...defargs) {
($ bloc (__suffix-dup a (- (argcount func) (len defargs))))
(fun (bloc) (func ...defargs bloc))
!{undef bloc}}}
($undef bloc)})
10 changes: 7 additions & 3 deletions String.ark
Original file line number Diff line number Diff line change
Expand Up @@ -135,11 +135,15 @@
(let _pattern_sz (len _pattern))

(while (!= -1 _idx) {
(mut _first_segment (str:slice _out 0 _idx))
(mut _next_segment (str:slice _out (+ _idx _pattern_sz) (- (len _out) (+ _idx _pattern_sz))))
(set _out (+
(str:slice _out 0 _idx)
_first_segment
_new
(str:slice _out (+ _idx _pattern_sz) (- (len _out) (+ _idx _pattern_sz)))))
(set _idx (str:find _out _pattern))})
_next_segment))
(set _idx (str:find _next_segment _pattern))
(if (!= -1 _idx)
(set _idx (+ _idx (len _first_segment) (len _new))))})
_out }))

# @brief Join a list of elements with a given string delimiter
Expand Down
190 changes: 190 additions & 0 deletions Testing.ark
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
# internal, do not use
(let _runner (fun (_name _callable) {
(mut _passed 0)
(mut _failed 0)
(mut _failures [])
(let _case_desc "")
(mut _cases [])
(mut _case_pointer 0)
(mut display_cases_success false)

(let _start_time (time))
# run test
(_callable)
(let _end_time (time))

# no newline, yet
(puts _name)
(if (> _passed 0)
(puts (str:format " - {} ✅" _passed)))
(if (> _failed 0)
(puts (str:format ", {} ❌" _failed)))

(puts (str:format " in {:2.3f}ms\n" (* 1000 (- _end_time _start_time))))

(mut _i 0)
(let _failures_count (len _failures))
(while (< _i _failures_count) {
(print " " (@ _failures _i))
(set _i (+ 1 _i))})

[_passed _failed]}))

(let _test_desc (fun (_desc)
(if (empty? _desc)
""
(str:format " for test '{}'" (head _desc)))))

# internal, do not use
# Has a _case_desc which also exists (empty) inside _runner so that tests without a
# case won't crash the testing library when trying to access the case name.
# Add the test name to a pile so that we can nicely print all the case names later.
# Update the pointer to current case to its old value later on
(let _case (fun (_case_desc _callable) {
(let _old_pointer _case_pointer)
(append! _cases _case_desc)
(_callable)
(pop! _cases -1)
(set _case_pointer _old_pointer)}))

# @brief Create a test case with a label to help with debugging when one or more tests fail
# @details Test cases can be nested.
# @param _desc a description for the test, a string
# @param _body test to execute
# =begin
# (test:suite name {
# (test:expect (my_function 1 2 3))
# (test:case "a description" {
# (test:expect (return_true) "return true"})
# (test:eq 1 2 "1 is 2, this should fail")})
# =end
# @author https://github.com/SuperFola
($ test:case (_desc _body)
(_case _desc (fun () {_body})))

# internal, do not use
# Until _case_pointer isn't at the end of the pile (where our failing test case's is),
# iterate on the list, writing the case name in a cascade pattern.
# This way if we have CASE A>CASE B>CASE C and no test crashed in A nor in A>B,
# we are still able to display the cascade A>B>C with the correct indentation.
(let _add_case (fun () {
(let _target_len (len _cases))
(while (< _case_pointer _target_len) {
(mut _indent (* 2 _case_pointer))
(mut _fmt (if (> _indent 0) (+ "{: <" (toString _indent) "}{}") "{}{}"))
(append! _failures (str:format _fmt "" (@ _cases _case_pointer)))
(set _case_pointer (+ 1 _case_pointer))})}))

# internal, do not use
# This can only be used within a (nested or not) call to test:suite
# because it updates _failed and _failures, which are defined by
# test:suite call to _runner
(let _report_error (fun (_lhs _rhs _lhs_repr _rhs_repr _desc) {
(set _failed (+ 1 _failed))

# If we have a case description AND the pointer isn't up to date, display the case(s)' names
(if (and (not (empty? _case_desc)) (!= _case_pointer (len _cases)))
(_add_case))

# Compute global indent for the failing test resume
(let _indent_case_len (* 2 (len _cases)))
(let _indent (if (> _indent_case_len 0)
(str:format (+ "{: <" (toString _indent_case_len) "}") "")
""))
# Add the error message
(append! _failures (str:format "{}expected '{}' but got '{}'{}" _indent _lhs_repr _rhs_repr (_test_desc _desc)))

(let _rhs_start (+ (len _lhs_repr) (len "expected ''")))
(let _lhs_align (len _lhs_repr))
(let _rhs_align (len _rhs_repr))
(let _show_expected (!= _lhs_repr (toString _lhs)))
(let _show_real (!= _rhs_repr (toString _rhs)))

(if _show_real
(append! _failures
(str:format
(+ "{}{: <" (toString (len "expected ")) "}" "{: <" (toString _rhs_start) "}{:~<" (toString _rhs_align) "} {}")
_indent
# to position one char before the first ' surrounding the expected value
""
# writes the | right under the first ' surrounding the expected value
(if _show_expected "|" "")
# begins the \~~~~ under the real value
(if _show_real "\\" "")
(if _show_real _rhs ""))))
(if _show_expected
(append! _failures
(str:format
(+ "{}{: <" (toString (len "expected ")) "}\\ {}")
_indent
""
_lhs)))}))

# internal, do not use
# This can only be used within a (nested or not) call to test:suite
# because it updates _passed, which is defined by test:suite call to _runner
(let _report_success (fun () {
(set _passed (+ 1 _passed))
(if display_cases_success
(_add_case))
}))

# @brief Given a value or function call returning a boolean, generate a test case
# @param _cond the value to test for truthiness
# @param _desc an optional description (string) for the test
# =begin
# (test:suite name {
# (test:expect (my_function 1 2 3))
# (test:expect (return_true) "return true"})
# =end
# @author https://github.com/SuperFola
($ test:expect (_cond ..._desc) {
(if (!= true _cond)
{
(set _failed (+ 1 _failed))
(append! _failures (str:format "{} returned {}{}" ($repr _cond) _cond) (_test_desc _desc))}
(_report_success))})

# @brief Compare two values that should be equal and generate a test case
# @param _expected expected value
# @param _expr computed value to test
# @param _desc an optional description (string) for the test
# =begin
# (test:suite name {
# (test:eq 6 (my_function 1 2 3))
# (test:eq 5 (foo) "foo should return 5")})
# =end
# @author https://github.com/SuperFola
($ test:eq (_expected _expr ..._desc) {
(if (= _expected _expr)
(_report_success)
(_report_error _expected _expr ($repr _expected) ($repr _expr) _desc))})

# @brief Compare two values that should **not** be equal and generate a test case
# @param _unexpected the value we don't want
# @param _value tested value
# @param _desc an optional description (string) for the test
# =begin
# (test:suite name {
# (test:neq 0 (my_function 1 2 3))})
# =end
# @author https://github.com/SuperFola
($ test:neq (_unexpected _value ..._desc) {
(if (!= _unexpected _value)
(_report_success)
(_report_error _unexpected _value ($repr _unexpected) ($repr _value) _desc))})

# @brief Generate the code for a test suite
# @details Create two variables: _name-output (a list: [successes, failures]) and _name-status (boolean, true on success)
# @param _name test name, as an identifier
# @param _body body of the test, a begin block
# =begin
# (test:suite name {
# (set display_cases_success true) # default: false, when true, display all the cases names on success and failures
# (test:eq 6 (my_function 1 2 3))
# (test:eq 128 (* 8 16))})
# =end
# @author https://github.com/SuperFola
($ test:suite (_name _body) {
(let (symcat _name "-output") (_runner ($repr _name) (fun () {_body})))
(let (symcat _name "-status") (= 0 (@ (symcat _name "-output") 1)))})
10 changes: 10 additions & 0 deletions tests/all.ark
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
(import events-tests)
(import exceptions-tests)
(import functional-tests)
(import lazy-tests)
(import list-tests)
(import macros-tests)
(import math-tests)
(import range-tests)
(import string-tests)
(import switch-tests)
Loading