diff --git a/analysis/dependency/file-linkage.sls b/analysis/dependency/file-linkage.sls index c811f9ee..95a303dc 100644 --- a/analysis/dependency/file-linkage.sls +++ b/analysis/dependency/file-linkage.sls @@ -25,6 +25,7 @@ (scheme-langserver analysis util) (scheme-langserver analysis dependency rules library-import) + (scheme-langserver analysis dependency rules library-import-r7rs) (scheme-langserver analysis dependency rules load) (scheme-langserver util dedupe) @@ -42,13 +43,16 @@ (mutable id->path-map) (mutable matrix))) -(define (init-file-linkage root-file-node root-library-node) - (let ([id->path-map (make-eq-hashtable)] - [path->id-map (make-hashtable string-hash equal?)]) - (init-maps root-library-node id->path-map path->id-map) - (let ([matrix (make-vector (* (hashtable-size id->path-map) (hashtable-size id->path-map)))]) - (init-matrix root-library-node root-file-node root-library-node path->id-map matrix) - (make-file-linkage path->id-map id->path-map matrix)))) +(define init-file-linkage + (case-lambda + [(root-file-node root-library-node) (init-file-linkage root-file-node root-library-node 'r6rs)] + [(root-file-node root-library-node top-environment) + (let ([id->path-map (make-eq-hashtable)] + [path->id-map (make-hashtable string-hash equal?)]) + (init-maps root-library-node id->path-map path->id-map) + (let ([matrix (make-vector (* (hashtable-size id->path-map) (hashtable-size id->path-map)))]) + (init-matrix root-library-node root-file-node root-library-node path->id-map matrix top-environment) + (make-file-linkage path->id-map id->path-map matrix)))])) (define (init-maps current-library-node id->path-map path->id-map) (let loop ([file-nodes (library-node-file-nodes current-library-node)]) @@ -59,41 +63,45 @@ (loop (cdr file-nodes))))) (map (lambda (node) (init-maps node id->path-map path->id-map)) (library-node-children current-library-node))) -(define (refresh-file-linkage&get-refresh-path linkage root-library-node file-node new-index-node-list new-library-identifier-list) - (let* ([path (file-node-path file-node)] - [path->id-map (file-linkage-path->id-map linkage)] - [id->path-map (file-linkage-id->path-map linkage)] - [old-node-count (sqrt (vector-length (file-linkage-matrix linkage)))] - [id (if (hashtable-ref path->id-map path #f) - (hashtable-ref path->id-map path #f) - (if (null? new-library-identifier-list) - '() - (begin - (hashtable-set! path->id-map path old-node-count) - (hashtable-set! id->path-map old-node-count path) - (file-linkage-matrix-set! linkage (matrix-expand (file-linkage-matrix linkage))) - old-node-count)))] - [reference-id-to (if (null? id) '() (filter (lambda (inner-id) (not (= inner-id id))) (linkage-matrix-to-recursive (file-linkage-matrix linkage) id)))] - [reference-id-from (if (null? id) '() (filter (lambda (inner-id) (not (= inner-id id))) (linkage-matrix-from-recursive (file-linkage-matrix linkage) id)))] - [matrix (file-linkage-matrix linkage)] - [old-imported-file-ids - (map - (lambda(p) (hashtable-ref path->id-map p #f)) - (get-reference-path-from linkage path))] - [new-imported-file-ids - (map - (lambda(p) (hashtable-ref path->id-map p #f)) - (apply append +(define refresh-file-linkage&get-refresh-path + (case-lambda + [(linkage root-library-node file-node new-index-node-list new-library-identifier-list) + (refresh-file-linkage&get-refresh-path linkage root-library-node file-node new-index-node-list new-library-identifier-list 'r6rs)] + [(linkage root-library-node file-node new-index-node-list new-library-identifier-list top-environment) + (let* ([path (file-node-path file-node)] + [path->id-map (file-linkage-path->id-map linkage)] + [id->path-map (file-linkage-id->path-map linkage)] + [old-node-count (sqrt (vector-length (file-linkage-matrix linkage)))] + [id (if (hashtable-ref path->id-map path #f) + (hashtable-ref path->id-map path #f) + (if (null? new-library-identifier-list) + '() + (begin + (hashtable-set! path->id-map path old-node-count) + (hashtable-set! id->path-map old-node-count path) + (file-linkage-matrix-set! linkage (matrix-expand (file-linkage-matrix linkage))) + old-node-count)))] + [reference-id-to (if (null? id) '() (filter (lambda (inner-id) (not (= inner-id id))) (linkage-matrix-to-recursive (file-linkage-matrix linkage) id)))] + [reference-id-from (if (null? id) '() (filter (lambda (inner-id) (not (= inner-id id))) (linkage-matrix-from-recursive (file-linkage-matrix linkage) id)))] + [matrix (file-linkage-matrix linkage)] + [old-imported-file-ids (map - (lambda (index-node) (get-imported-libraries-from-index-node root-library-node index-node)) - new-index-node-list)))]) - (if (null? id) - ;;todo shrink matrix - '() - (begin - (map (lambda(row-id) (matrix-set! matrix row-id id 0)) old-imported-file-ids) - (map (lambda(column-id) (matrix-set! matrix id column-id 1)) (dedupe new-imported-file-ids)) - (map (lambda(current-id) (hashtable-ref id->path-map current-id #f)) `(,@reference-id-from ,id ,@reference-id-to)))))) + (lambda(p) (hashtable-ref path->id-map p #f)) + (get-reference-path-from linkage path))] + [new-imported-file-ids + (map + (lambda(p) (hashtable-ref path->id-map p #f)) + (apply append + (map + (lambda (index-node) (get-imported-libraries-from-index-node root-library-node index-node top-environment)) + new-index-node-list)))]) + (if (null? id) + ;;todo shrink matrix + '() + (begin + (map (lambda(row-id) (matrix-set! matrix row-id id 0)) old-imported-file-ids) + (map (lambda(column-id) (matrix-set! matrix id column-id 1)) (dedupe new-imported-file-ids)) + (map (lambda(current-id) (hashtable-ref id->path-map current-id #f)) `(,@reference-id-from ,id ,@reference-id-to)))))])) (define (get-reference-path-to linkage to-path) (let* ([matrix (file-linkage-matrix linkage)] @@ -234,45 +242,56 @@ (hashtable-ref (file-linkage-path->id-map linkage) from #f) (hashtable-ref (file-linkage-path->id-map linkage) to #f))) -(define (get-imported-libraries-from-index-node root-library-node index-node) - (apply append - (map - (lambda (l) (map file-node-path (library-node-file-nodes l))) - (filter (lambda (l) - (if (null? l) #f (not (null? (library-node-file-nodes l))))) - (map - (lambda (id) (walk-library id root-library-node)) - (library-import-process index-node)))))) - -(define (init-matrix current-library-node root-file-node root-library-node path->id-map matrix) - (let loop ([file-nodes (library-node-file-nodes current-library-node)]) - (if (pair? file-nodes) - (let* ([file-node (car file-nodes)] - [path (file-node-path file-node)] - [imported-libraries - (dedupe (apply append - (map (lambda (index-node) (get-imported-libraries-from-index-node root-library-node index-node)) - (document-index-node-list (file-node-document file-node)))))] - [loaded-files - (dedupe (apply append - (map (lambda (index-node) (load-process root-file-node (file-node-document file-node) index-node)) - (document-index-node-list (file-node-document file-node)))))]) - - (map (lambda (imported-library-path) - (if (not (null? imported-library-path)) - (matrix-set! matrix - (hashtable-ref path->id-map path #f) - (hashtable-ref path->id-map imported-library-path #f)))) - imported-libraries) +(define get-imported-libraries-from-index-node + (case-lambda + [(root-library-node index-node) (get-imported-libraries-from-index-node root-library-node index-node 'r6rs)] + [(root-library-node index-node top-environment) + (let ([func (case top-environment + ['r6rs library-import-process] + ['r7rs library-import-process-r7rs])]) + (apply append + (map + (lambda (l) (map file-node-path (library-node-file-nodes l))) + (filter (lambda (l) + (if (null? l) #f (not (null? (library-node-file-nodes l))))) + (map + (lambda (id) (walk-library id root-library-node)) + (func index-node))))))])) - (map (lambda (file-node) - (matrix-set! matrix - (hashtable-ref path->id-map path #f) - (hashtable-ref path->id-map (file-node-path file-node) #f))) - loaded-files) +(define init-matrix + (case-lambda + [(current-library-node root-file-node root-library-node path->id-map matrix) (init-matrix current-library-node root-file-node root-library-node path->id-map matrix 'r6rs)] + [(current-library-node root-file-node root-library-node path->id-map matrix top-environment) + (let loop ([file-nodes (library-node-file-nodes current-library-node)]) + (if (pair? file-nodes) + (let* ([file-node (car file-nodes)] + [path (file-node-path file-node)] + [imported-libraries + (dedupe (apply append + (map (lambda (index-node) (get-imported-libraries-from-index-node root-library-node index-node top-environment)) + (document-index-node-list (file-node-document file-node)))))] + [loaded-files + (dedupe (apply append + (map (lambda (index-node) (load-process root-file-node (file-node-document file-node) index-node)) + (document-index-node-list (file-node-document file-node)))))]) + + (map (lambda (imported-library-path) + (if (not (null? imported-library-path)) + (matrix-set! matrix + (hashtable-ref path->id-map path #f) + (hashtable-ref path->id-map imported-library-path #f)))) + imported-libraries) + + (map (lambda (file-node) + (matrix-set! matrix + (hashtable-ref path->id-map path #f) + (hashtable-ref path->id-map (file-node-path file-node) #f))) + loaded-files) + + (loop (cdr file-nodes))))) - (loop (cdr file-nodes))))) - (map (lambda (node) - (init-matrix node root-file-node root-library-node path->id-map matrix)) - (library-node-children current-library-node))) + (map (lambda (node) + (init-matrix node root-file-node root-library-node path->id-map matrix top-environment)) + (library-node-children current-library-node)) + ])) ) \ No newline at end of file diff --git a/analysis/dependency/rules/library-import-r7rs.sls b/analysis/dependency/rules/library-import-r7rs.sls new file mode 100644 index 00000000..2415105d --- /dev/null +++ b/analysis/dependency/rules/library-import-r7rs.sls @@ -0,0 +1,44 @@ +(library (scheme-langserver analysis dependency rules library-import-r7rs) + (export + library-import-process-r7rs) + (import + (chezscheme) + (ufo-match) + + (scheme-langserver analysis identifier reference) + (ufo-try) + + (scheme-langserver virtual-file-system index-node) + (scheme-langserver virtual-file-system document) + (scheme-langserver virtual-file-system file-node)) + +(define (library-import-process-r7rs index-node) + (apply append + (let* ([ann (index-node-datum/annotations index-node)] + [expression (annotation-stripped ann)]) + (match expression + [('define-library _ **1 ) (map match-import (index-node-children index-node))] + [else (list (match-import index-node))])))) + +(define (match-import index-node) + (filter + (lambda (item) (not (null? item))) + (let* ([ann (index-node-datum/annotations index-node)] + [expression (annotation-stripped ann)]) + (match expression + [('import dummy **1 ) (map match-clause (index-node-children index-node))] + [else '()])))) + +(define (match-clause index-node) + (filter + (lambda (item) (not (null? item))) + (let* ([ann (index-node-datum/annotations index-node)] + [expression (annotation-stripped ann)]) + (match expression + [('only (identifier **1) _ ...) identifier] + [('except (identifier **1) _ ...) identifier] + [('prefix (identifier **1) _ ...) identifier] + [('rename (identifier **1) _ ...) identifier] + [(identifier **1) identifier] + [else '()])))) +) \ No newline at end of file diff --git a/analysis/util.sls b/analysis/util.sls index 2aecd297..4274b089 100644 --- a/analysis/util.sls +++ b/analysis/util.sls @@ -17,18 +17,26 @@ (define (do-nothing . fuzzy) (void)) -(define (get-library-identifiers-list document) - (if (null? document) - '() - (let ([index-node-list (document-index-node-list document)]) - (dedupe - (map - (lambda (index-node) - (match (annotation-stripped (index-node-datum/annotations index-node)) - [('library (name **1) _ ... ) name] - [('define-library (name **1) _ ... ) name] - [else '()])) - index-node-list))))) +(define get-library-identifiers-list + (case-lambda + [(document) (get-library-identifiers-list document 'r6rs)] + [(document top-environment) + (let [(func (case top-environment + ['r6rs + (lambda (index-node) + (match (annotation-stripped (index-node-datum/annotations index-node)) + [('library (name **1) _ ... ) name] + [else '()]))] + ['r7rs + (lambda (index-node) + (match (annotation-stripped (index-node-datum/annotations index-node)) + [('define-library (name **1) _ ... ) name] + [else '()]))]))] + (if (null? document) + '() + (let ([index-node-list (document-index-node-list document)]) + (dedupe + (map func index-node-list)))))])) (define (get-nearest-ancestor-library-identifier index-node) (if (null? index-node) diff --git a/analysis/workspace.sls b/analysis/workspace.sls index fb358c80..0eb9aa66 100644 --- a/analysis/workspace.sls +++ b/analysis/workspace.sls @@ -74,8 +74,8 @@ (define (refresh-workspace workspace-instance) (let* ([path (file-node-path (workspace-file-node workspace-instance))] [root-file-node (init-virtual-file-system path '() (workspace-facet workspace-instance) (workspace-top-environment workspace-instance))] - [root-library-node (init-library-node root-file-node)] - [file-linkage (init-file-linkage root-file-node root-library-node)] + [root-library-node (init-library-node root-file-node (workspace-top-environment workspace-instance))] + [file-linkage (init-file-linkage root-file-node root-library-node (workspace-top-environment workspace-instance))] [batches (get-init-reference-batches file-linkage)]) (init-references workspace-instance batches) (workspace-file-node-set! workspace-instance root-file-node) @@ -97,8 +97,8 @@ [akku (generate-akku-acceptable-file-filter (string-append path "/.akku/list"))] [else (generate-akku-acceptable-file-filter (string-append path "/.akku/list"))])] [root-file-node (init-virtual-file-system path '() facet top-environment)] - [root-library-node (init-library-node root-file-node)] - [file-linkage (init-file-linkage root-file-node root-library-node)] + [root-library-node (init-library-node root-file-node top-environment)] + [file-linkage (init-file-linkage root-file-node root-library-node top-environment)] [batches (get-init-reference-batches file-linkage)]) (init-references root-file-node root-library-node file-linkage threaded? batches type-inference?) (make-workspace root-file-node root-library-node file-linkage facet threaded? type-inference? top-environment))])) @@ -159,8 +159,7 @@ [linkage (workspace-file-linkage workspace-instance)] [target-document (file-node-document target-file-node)] [root-library-node (workspace-library-node workspace-instance)] - - [old-library-identifiers-list (get-library-identifiers-list (file-node-document target-file-node))] + [old-library-identifiers-list (get-library-identifiers-list (file-node-document target-file-node) (workspace-top-environment workspace-instance))] [old-library-node-list (filter (lambda (item) (not (null? item))) (map (lambda (old-library-identifiers) (walk-library old-library-identifiers root-library-node)) @@ -177,7 +176,7 @@ (document-line-length-vector-set! target-document (text->line-length-vector text)) (document-index-node-list-set! target-document new-index-nodes) - (let ([new-library-identifiers-list (get-library-identifiers-list (file-node-document target-file-node))]) + (let ([new-library-identifiers-list (get-library-identifiers-list (file-node-document target-file-node) (workspace-top-environment workspace-instance))]) (if (not (equal? new-library-identifiers-list old-library-identifiers-list)) (begin ;; BEGINE: some file may change their library-identifier or even do not have library identifier, their should be process carefully. @@ -199,7 +198,7 @@ (if (walk-library library-identifiers root-library-node) (generate-library-node library-identifiers root-library-node target-file-node))) new-library-identifiers-list) - (workspace-file-linkage-set! workspace-instance (init-file-linkage root-file-node root-library-node)) + (workspace-file-linkage-set! workspace-instance (init-file-linkage root-file-node root-library-node (workspace-top-environment workspace-instance))) ;;For new dependency (map (lambda (document) (document-refreshable?-set! document #t)) (map (lambda (path) (file-node-document (walk-file root-file-node path))) @@ -211,10 +210,10 @@ (let* ([linkage (workspace-file-linkage workspace-instance)] [root-file-node (workspace-file-node workspace-instance)] [root-library-node (workspace-library-node workspace-instance)] - [library-identifiers-list (get-library-identifiers-list (file-node-document target-file-node))]) + [library-identifiers-list (get-library-identifiers-list (file-node-document target-file-node) (workspace-top-environment workspace-instance))]) (if (null? library-identifiers-list) (init-references workspace-instance `((,(file-node-path target-file-node)))) - (let* ([path (refresh-file-linkage&get-refresh-path linkage root-library-node target-file-node (document-index-node-list (file-node-document target-file-node)) library-identifiers-list)] + (let* ([path (refresh-file-linkage&get-refresh-path linkage root-library-node target-file-node (document-index-node-list (file-node-document target-file-node)) library-identifiers-list (workspace-top-environment workspace-instance))] [path-aheadof `(,@(list-ahead-of path (file-node-path target-file-node)) ,(file-node-path target-file-node))] [refreshable-path (filter (lambda (single) (document-refreshable? (file-node-document (walk-file root-file-node single)))) path-aheadof)] ;target-file-node may don't have library-identifiers-list @@ -321,15 +320,16 @@ (define init-library-node (case-lambda - [(file-node) (init-library-node file-node (make-library-node '() '() '() '())) ] - [(file-node root-library-node) + [(file-node) (init-library-node file-node 'r6rs (make-library-node '() '() '() '()) )] + [(file-node top-environment) (init-library-node file-node top-environment (make-library-node '() '() '() '()))] + [(file-node top-environment root-library-node) (if (file-node-folder? file-node) (map - (lambda (child-node) (init-library-node child-node root-library-node)) + (lambda (child-node) (init-library-node child-node top-environment root-library-node)) (file-node-children file-node)) (map (lambda (library-identifiers) (generate-library-node library-identifiers root-library-node file-node)) - (get-library-identifiers-list (file-node-document file-node)))) + (get-library-identifiers-list (file-node-document file-node) top-environment))) root-library-node])) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; diff --git a/tests/analysis/dependency/rules/test-library-import.sps b/tests/analysis/dependency/rules/test-library-import.sps index 8270b682..743e05ab 100755 --- a/tests/analysis/dependency/rules/test-library-import.sps +++ b/tests/analysis/dependency/rules/test-library-import.sps @@ -12,6 +12,7 @@ (scheme-langserver virtual-file-system index-node) (scheme-langserver analysis dependency rules library-import) + (scheme-langserver analysis dependency rules library-import-r7rs) (scheme-langserver analysis package-manager akku) (scheme-langserver analysis workspace) (scheme-langserver analysis dependency file-linkage)) @@ -28,4 +29,16 @@ (test-equal '((chezscheme) (srfi :37 args-fold) (scheme-langserver)) (car (map library-import-process root-index-nodes)))) (test-end) +(test-begin "library-import-process for r7rs liii") + (let* ([root-file-node (init-virtual-file-system "./tests/resources/r7rs/liii/rich-vector.scm.txt" '() (lambda (fuzzy) #t) 'r7rs)] + [root-index-nodes (document-index-node-list (file-node-document root-file-node))]) + (test-equal '((liii string) (liii hash-table) (liii sort) (liii list) (liii vector) (liii oop) (srfi srfi-8)) (car (map library-import-process-r7rs root-index-nodes)))) +(test-end) + +(test-begin "library-import-process for r7rs srfi") + (let* ([root-file-node (init-virtual-file-system "./tests/resources/r7rs/srfi/sicp.scm.txt" '() (lambda (fuzzy) #t) 'r7rs)] + [root-index-nodes (document-index-node-list (file-node-document root-file-node))]) + (test-equal '((srfi srfi-216)) (car (map library-import-process-r7rs root-index-nodes)))) +(test-end) + (exit (if (zero? (test-runner-fail-count (test-runner-get))) 0 1)) diff --git a/tests/analysis/dependency/test-file-linkage.sps b/tests/analysis/dependency/test-file-linkage.sps index 73312798..271a62c0 100755 --- a/tests/analysis/dependency/test-file-linkage.sps +++ b/tests/analysis/dependency/test-file-linkage.sps @@ -10,6 +10,7 @@ (scheme-langserver virtual-file-system file-node) (scheme-langserver analysis workspace) (scheme-langserver analysis package-manager akku) + (scheme-langserver analysis package-manager txt-filter) (scheme-langserver analysis dependency file-linkage)) (test-begin "init-linkage-matrix") @@ -41,4 +42,33 @@ (car paths))) (test-end) +(test-begin "init-linkage-matrix-r7rs") + (let* ([root-file-node (init-virtual-file-system (current-directory) '() (generate-txt-file-filter) 'r7rs)] + [root-library-node (init-library-node root-file-node 'r7rs)] + [file-linkage (init-file-linkage root-file-node root-library-node 'r7rs)] + [from-path (string-append (current-directory) "/tests/resources/r7rs/liii/rich-vector.scm.txt")] + [to-path (string-append (current-directory) "/tests/resources/r7rs/srfi/srfi-8.scm.txt")]) + (test-equal 1 (file-linkage-take file-linkage from-path to-path))) +(test-end) + +(test-begin "get-init-inference-path-r7rs") + (let* ([root-file-node (init-virtual-file-system (current-directory) '() (generate-txt-file-filter) 'r7rs)] + [root-library-node (init-library-node root-file-node 'r7rs)] + [file-linkage (init-file-linkage root-file-node root-library-node 'r7rs)] + [paths (apply append (get-init-reference-batches file-linkage))] + [target-path (string-append (current-directory) "/tests/resources/r7rs/scheme/base.scm.txt")]) + (test-equal target-path (find (lambda (p) (equal? target-path p)) paths))) +(test-end) + +(test-begin "file-linkage-to-r7rs") + (let* ([root-file-node (init-virtual-file-system (current-directory) '() (generate-txt-file-filter) 'r7rs)] + [root-library-node (init-library-node root-file-node 'r7rs)] + [file-linkage (init-file-linkage root-file-node root-library-node 'r7rs)] + [to-path (string-append (current-directory) "/tests/resources/r7rs/srfi/srfi-8.scm.txt")] + [paths (file-linkage-to file-linkage to-path)]) + (test-equal + (string-append (current-directory) "/tests/resources/r7rs/liii/rich-vector.scm.txt") + (car paths))) +(test-end) + (exit (if (zero? (test-runner-fail-count (test-runner-get))) 0 1)) diff --git a/tests/resources/r7rs/liii/rich-vector.scm.txt b/tests/resources/r7rs/liii/rich-vector.scm.txt new file mode 100644 index 00000000..ad6e4526 --- /dev/null +++ b/tests/resources/r7rs/liii/rich-vector.scm.txt @@ -0,0 +1,446 @@ +; +; Copyright (C) 2025 The Goldfish Scheme Authors +; +; Licensed under the Apache License, Version 2.0 (the "License"); +; you may not use this file except in compliance with the License. +; You may obtain a copy of the License at +; +; http://www.apache.org/licenses/LICENSE-2.0 +; +; Unless required by applicable law or agreed to in writing, software +; distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +; WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +; License for the specific language governing permissions and limitations +; under the License. +; + +(define-library (liii rich-vector) +(import (liii string) (liii hash-table) (liii sort) (liii list) (liii vector) (liii oop) (srfi srfi-8)) +(export rich-vector) +(begin + +(define-case-class rich-vector ((data vector?)) + +(define (@range start end . step) + (let ((step-size (if (null? step) 1 (car step)))) + (cond + ((and (positive? step-size) (>= start end)) + (rich-vector #())) + ((and (negative? step-size) (<= start end)) + (rich-vector #())) + ((zero? step-size) + (value-error "Step size cannot be zero")) + (else + (let ((cnt (ceiling (/ (- end start) step-size)))) + (rich-vector (list->vector (iota cnt start step-size)))))))) + +(define (@empty . args) + (chain-apply args + (rich-vector #()))) + +(define (@fill n elem . args) + (unless (integer? n) + (type-error "n must be integer" n)) + (when (< n 0) + (value-error "n must be non-negative" n)) + (chain-apply args + (rich-vector (make-vector n elem)))) + +(define (%collect) data) + +(define (%length) + (vector-length data)) + +(define (%size) + (vector-length data)) + +(define (%apply i) + (when (or (< i 0) (>= i (vector-length data))) + (index-error "rich-vector%apply: out of range with index" i)) + (vector-ref data i)) + +(define (%index-of x) + (or (vector-index (lambda (y) (class=? x y)) data) + -1)) + +(define (%last-index-of x) + (or (vector-index-right (lambda (y) (class=? x y)) data) + -1)) + +(define (%find p) + (let loop ((i 0)) + (cond + ((>= i (vector-length data)) (none)) + ((p (vector-ref data i)) (option (vector-ref data i))) + (else (loop (+ i 1)))))) + +(define (%find-last pred) + (let loop ((i (- (vector-length data) 1))) + (cond + ((< i 0) (none)) ; 遍历完所有元素未找到 + ((pred (vector-ref data i)) (option (vector-ref data i))) ; 找到符合条件的元素 + (else (loop (- i 1)))))) ; 继续向前查找 + +(define (%head) + (if (> (vector-length data) 0) + (vector-ref data 0) + (error 'out-of-range "out-of-range"))) + +(define (%head-option) + (if (> (vector-length data) 0) + (option (vector-ref data 0)) + (none))) + +(define (%last) + (let ((len (vector-length data))) + (if (> len 0) + (vector-ref data (- len 1)) + (index-error "rich-vector%last: empty vector")))) + +(define (%last-option) + (let ((len (vector-length data))) + (if (> len 0) + (option (vector-ref data (- len 1))) + (none)))) + +(define (%slice from until . args) + (chain-apply args + (let* ((len (vector-length data)) + (start (max 0 from)) + (end (min len until))) + (if (< start end) + (rich-vector (vector-copy data start end)) + (rich-vector :empty))))) + +(define (%empty?) + (= (length data) 0)) + +(define (%equals that) + (and (that :is-instance-of 'rich-vector) + (vector= class=? data (that 'data)))) + +(define (%forall p) + (vector-every p data)) + +(define (%exists p) + (vector-any p data)) + +(define (%contains elem) + (%exists (lambda (x) (equal? x elem)))) + +(define (%map x . args) + (chain-apply args + (rich-vector (vector-map x data)))) + +(define (%flat-map f . args) + (chain-apply args + (rich-vector (%map f :reduce vector-append)))) + +(define (%filter x . args) + (chain-apply args + (rich-vector (vector-filter x data)))) + +(define (%for-each x) + (vector-for-each x data)) + +(define (%reverse . args) + (chain-apply args + (rich-vector (reverse data)))) + +(define (%count . xs) + (cond ((null? xs) (vector-length data)) + ((length=? 1 xs) (count (car xs) (vector->list data))) + (else (error 'wrong-number-of-args "rich-vector%count" xs)))) + +(define (%take n . args) + (define (scala-take data n) + (cond + ((< n 0) (vector)) + ((>= n (vector-length data)) data) + (else + (let ((new-vec (make-vector n))) + (do ((i 0 (+ i 1))) + ((>= i n) new-vec) + (vector-set! new-vec i (vector-ref data i))))))) + + (chain-apply args + (rich-vector (scala-take data n)))) + +(define (%take-right n . args) + (define (scala-take-right data n) + (let ((len (vector-length data))) + (cond + ((< n 0) (vector)) + ((>= n len) data) + (else + (let ((new-vec (make-vector n))) + (do ((i (- len n) (+ i 1)) + (j 0 (+ j 1))) + ((>= j n) new-vec) + (vector-set! new-vec j (vector-ref data i)))))))) + + (chain-apply args + (rich-vector (scala-take-right data n)))) + +(define (%drop n . args) + (define (scala-drop data n) + (cond + ((< n 0) data) + ((>= n (vector-length data)) (vector)) + (else (vector-copy data n)))) + (chain-apply args + (rich-vector (scala-drop data n)))) + +(define (%drop-right n . args) + (define (scala-drop-right data n) + (cond + ((< n 0) data) + ((>= n (vector-length data)) (vector)) + (else (vector-copy data 0 (- (vector-length data) n))))) + + (chain-apply args + (rich-vector (scala-drop-right data n)))) + +(define (%drop-while pred . args) + (chain-apply args + (let ((len (vector-length data))) + (let loop ((i 0)) + (cond + ((>= i len) (rich-vector :empty)) ; 所有元素都被丢弃 + ((pred (vector-ref data i)) (loop (+ i 1))) ; 继续丢弃 + (else (rich-vector (vector-copy data i)))))))) ; 返回剩余部分 + +(define (%fold initial f) + (vector-fold f initial data)) + +(define (%fold-right initial f) + (vector-fold-right f initial data)) + +(define (%count . xs) + (cond ((null? xs) (vector-length data)) + ((length=? 1 xs) (count (car xs) (vector->list data))) + (else (error 'wrong-number-of-args "rich-vector%count" xs)))) + +(define (%sort-with less-p . args) + (chain-apply args + (rich-vector (vector-stable-sort less-p data)))) + +(define (%sort-by f . args) + (chain-apply args + (let ((sorted-data (vector-stable-sort (lambda (x y) (< (f x) (f y))) data))) + (rich-vector sorted-data)))) + +(define (%group-by func) + (let ((group (make-hash-table))) + (for-each + (lambda (elem) + (let ((key (func elem))) + (hash-table-update!/default + group + key + (lambda (current-list) (cons elem current-list)) + '()))) + (vector->list data)) + (hash-table-for-each + (lambda (k v) (hash-table-set! group k (reverse-list->vector v))) + group) + (rich-hash-table group))) + +(define (%sliding size . step-arg) + (unless (integer? size) (type-error "rich-vector%sliding: size must be an integer " size)) + (unless (> size 0) (value-error "rich-vector%sliding: size must be a positive integer " size)) + + (let ((N (vector-length data))) + (if (zero? N) + #() + (let* ((is-single-arg-case (null? step-arg)) + (step (if is-single-arg-case 1 (car step-arg)))) + + ;; Validate step if provided + (when (and (not is-single-arg-case) + (or (not (integer? step)) (<= step 0))) + (if (not (integer? step)) + (type-error "rich-vector%sliding: step must be an integer " step) + (value-error "rich-vector%sliding: step must be a positive integer " step))) + + ;; single-argument version when N < size + (if (and is-single-arg-case (< N size)) + (vector data) + (let collect-windows ((current-idx 0) (result-windows '())) + (cond + ;; Stop if current_idx is out of bounds + ((>= current-idx N) (list->vector (reverse result-windows))) + ;; For single-arg case + ((and is-single-arg-case (> (+ current-idx size) N)) + (list->vector (reverse result-windows))) + (else + (let* ((window-end (if is-single-arg-case + (+ current-idx size) ;; Single-arg: always takes full 'size' + (min (+ current-idx size) N))) ;; Two-arg: can be partial + (current-window (vector-copy data current-idx window-end))) + (collect-windows (+ current-idx step) (cons current-window result-windows))))))))))) + +(define (%zip-with-index . args) + (chain-apply args + (let* ((n (vector-length data)) + (result (make-vector n))) + (let loop ((idx 0)) + (if (>= idx n) + (rich-vector result) + (begin + (vector-set! + result + idx + (cons idx (vector-ref data idx))) + (loop (+ idx 1)))))))) + +(define (%distinct . args) + (chain-apply args + (let ((ht (make-hash-table)) + (length (vector-length data))) + (let loop ((result '()) + (index 0)) + (if (>= index length) + (rich-vector (list->vector (reverse result))) + (let ((elem (vector-ref data index))) + (if (eq? (hash-table-ref ht elem) #f) + (begin + (hash-table-set! ht elem #t) + (loop (cons elem result) (+ index 1))) + (loop result (+ index 1))))))))) + +(define (%reduce f) + (let ((len (vector-length data))) + (if (zero? len) + (value-error "rich-vector%reduce: empty vector is not allowed to reduce") + (let loop ((acc (vector-ref data 0)) + (i 1)) + (if (>= i len) + acc + (loop (f acc (vector-ref data i)) (+ i 1))))))) + +(define (%index-where pred) + (or (vector-index pred data) + -1)) + +(define (%last-index-where pred) + (or (vector-index-right pred data) + -1)) + +(define (%take-while pred . args) + (chain-apply args + (let* ((vec data) + (len (vector-length vec)) + (idx (vector-index (lambda (x) (not (pred x))) vec))) + (rich-vector (vector-copy vec 0 (or idx len)))))) + +(define (%max-by f) + (when (not (procedure? f)) + (type-error "rich-vector%max-by: f must be a procedure")) + + (let ((vec data) + (len (length data))) + (if (zero? len) + (value-error "rich-vector%max-by: empty list is not allowed") + (let loop ((i 1) + (max-elem (vector-ref vec 0)) + (max-val (f (vector-ref vec 0)))) + (if (>= i len) + max-elem + (let* ((current-elem (vector-ref vec i)) + (current-val (f current-elem))) + (unless (number? current-val) + (type-error "f must return a number")) + (if (< current-val max-val) + (loop (+ i 1) max-elem max-val) + (loop (+ i 1) current-elem current-val)))))))) + +(define (%min-by f) + (when (not (procedure? f)) + (type-error "rich-vector%min-by: f must be a procedure")) + + (let ((vec data) + (len (length data))) + (if (zero? len) + (value-error "rich-vector%min-by: empty list is not allowed") + (let loop ((i 1) + (min-elem (vector-ref vec 0)) + (min-val (f (vector-ref vec 0)))) + (if (>= i len) + min-elem + (let* ((current-elem (vector-ref vec i)) + (current-val (f current-elem))) + (unless (number? current-val) + (type-error "f must return a number")) + (if (> current-val min-val) + (loop (+ i 1) min-elem min-val) + (loop (+ i 1) current-elem current-val)))))))) + +(define (%max-by-option f) + (when (not (procedure? f)) + (type-error "rich-vector%max-by-option: f must be a procedure")) + + (if (zero? (vector-length data)) + (none) + (option (%max-by f)))) + +(define (%min-by-option f) + (when (not (procedure? f)) + (type-error "rich-vector%min-by-option: f must be a procedure")) + + (if (zero? (vector-length data)) + (none) + (option (%min-by f)))) + +(define (%to-string) + ((%map object->string) + :make-string "#(" " " ")")) + +(define (%make-string . xs) + (define (parse-args xs) + (cond + ((null? xs) (values "" "" "")) + ((length=? 1 xs) + (let ((sep (car xs))) + (if (string? sep) + (values "" sep "") + (type-error "rich-vector%make-string: separator must be a string" sep)))) + ((length=? 2 xs) + (error 'wrong-number-of-args "rich-vector%make-string: expected 0, 1, or 3 arguments, but got 2" xs)) + ((length=? 3 xs) + (let ((start (car xs)) + (sep (cadr xs)) + (end (caddr xs))) + (if (and (string? start) (string? sep) (string? end)) + (values start sep end) + (type-error "rich-vector%make-string: prefix, separator, and suffix must be strings" xs)))) + (else (error 'wrong-number-of-args "rich-vector%make-string: expected 0, 1, or 3 arguments" xs)))) + + (receive (start sep end) (parse-args xs) + (let* ((as-string (lambda (x) (if (string? x) x (object->string x)))) + (middle (string-join (map as-string (vector->list data)) sep))) + (string-append start middle end)))) + +(define (%to-list) + (vector->list data)) + +(define (%to-rich-list) + (rich-list (vector->list data))) + +(define (%set! i x) + (when (or (< i 0) (>= i (length data))) + (index-error "rich-vector%set! out of range at index" i)) + (vector-set! data i x)) + +(define (%append v) + (when (not (or (vector? v) (rich-vector :is-type-of v))) + (type-error "rich-vector%append: input is not vector or rich-vector")) + + (if (vector? v) + (rich-vector (vector-append data v)) + (rich-vector (vector-append data (v :collect))))) + +) ; end of define-case-class + +) ; end of begin +) ; end of define-library diff --git a/tests/resources/r7rs/base.scm.txt b/tests/resources/r7rs/scheme/base.scm.txt similarity index 100% rename from tests/resources/r7rs/base.scm.txt rename to tests/resources/r7rs/scheme/base.scm.txt diff --git a/tests/resources/r7rs/boot.scm.txt b/tests/resources/r7rs/scheme/boot.scm.txt similarity index 100% rename from tests/resources/r7rs/boot.scm.txt rename to tests/resources/r7rs/scheme/boot.scm.txt diff --git a/tests/resources/r7rs/case-lambda.scm.txt b/tests/resources/r7rs/scheme/case-lambda.scm.txt similarity index 100% rename from tests/resources/r7rs/case-lambda.scm.txt rename to tests/resources/r7rs/scheme/case-lambda.scm.txt diff --git a/tests/resources/r7rs/char.scm.txt b/tests/resources/r7rs/scheme/char.scm.txt similarity index 100% rename from tests/resources/r7rs/char.scm.txt rename to tests/resources/r7rs/scheme/char.scm.txt diff --git a/tests/resources/r7rs/file.scm.txt b/tests/resources/r7rs/scheme/file.scm.txt similarity index 100% rename from tests/resources/r7rs/file.scm.txt rename to tests/resources/r7rs/scheme/file.scm.txt diff --git a/tests/resources/r7rs/inexact.scm.txt b/tests/resources/r7rs/scheme/inexact.scm.txt similarity index 100% rename from tests/resources/r7rs/inexact.scm.txt rename to tests/resources/r7rs/scheme/inexact.scm.txt diff --git a/tests/resources/r7rs/process-context.scm.txt b/tests/resources/r7rs/scheme/process-context.scm.txt similarity index 100% rename from tests/resources/r7rs/process-context.scm.txt rename to tests/resources/r7rs/scheme/process-context.scm.txt diff --git a/tests/resources/r7rs/time.scm.txt b/tests/resources/r7rs/scheme/time.scm.txt similarity index 100% rename from tests/resources/r7rs/time.scm.txt rename to tests/resources/r7rs/scheme/time.scm.txt diff --git a/tests/resources/r7rs/srfi/sicp.scm.txt b/tests/resources/r7rs/srfi/sicp.scm.txt new file mode 100644 index 00000000..03715b7f --- /dev/null +++ b/tests/resources/r7rs/srfi/sicp.scm.txt @@ -0,0 +1,20 @@ +; +; Copyright (C) 2024 The Goldfish Scheme Authors +; +; Licensed under the Apache License, Version 2.0 (the "License"); +; you may not use this file except in compliance with the License. +; You may obtain a copy of the License at +; +; http://www.apache.org/licenses/LICENSE-2.0 +; +; Unless required by applicable law or agreed to in writing, software +; distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +; WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +; License for the specific language governing permissions and limitations +; under the License. +; + +(define-library (srfi sicp) +(export true false nil runtime) +(import (srfi srfi-216))) + diff --git a/tests/resources/r7rs/srfi/srfi-8.scm.txt b/tests/resources/r7rs/srfi/srfi-8.scm.txt new file mode 100644 index 00000000..c8c952ff --- /dev/null +++ b/tests/resources/r7rs/srfi/srfi-8.scm.txt @@ -0,0 +1,28 @@ +; +; Copyright (C) 2024 The Goldfish Scheme Authors +; +; Licensed under the Apache License, Version 2.0 (the "License"); +; you may not use this file except in compliance with the License. +; You may obtain a copy of the License at +; +; http://www.apache.org/licenses/LICENSE-2.0 +; +; Unless required by applicable law or agreed to in writing, software +; distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +; WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +; License for the specific language governing permissions and limitations +; under the License. +; + +(define-library (srfi srfi-8) +(export receive) +(begin + +(define-macro (receive formals expression . body) + `(call-with-values + (lambda () (values ,expression)) + (lambda ,formals ,@body))) + +) ; end of begin +) ; end of define-library +