Skip to content

Commit

Permalink
Merge pull request #37 from ArkScript-lang/v4
Browse files Browse the repository at this point in the history
V4
  • Loading branch information
SuperFola authored Mar 8, 2024
2 parents 4fa96f9 + c3520e8 commit 9107dc2
Show file tree
Hide file tree
Showing 18 changed files with 464 additions and 414 deletions.
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

0 comments on commit 9107dc2

Please sign in to comment.