Skip to content
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

Tests #5

Merged
merged 32 commits into from
Oct 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
0b775f5
Start on tests
Bike Sep 29, 2023
226651c
Use Ecclessia instead of trivial-cltl2 for parse-macro
Bike Sep 29, 2023
cf242b6
Define Trucler query methods for our environments
Bike Sep 29, 2023
7127b95
define sham INCF for tests
Bike Sep 29, 2023
c47d1c7
Signal actual program-errors on lambda list problems
Bike Sep 29, 2023
fc9f0e2
Compile m-v-call w/o using etypecase macro
Bike Sep 29, 2023
f9979d9
Allow docstrings in lambda expressions
Bike Sep 29, 2023
e4c7d22
Fix lambda handling of special declarations
Bike Sep 29, 2023
6a1d338
Implicit blocks for LABELS functions
Bike Sep 29, 2023
50ec6cf
Correctly treat :allow-other-keys as a normal keyword argument
Bike Sep 29, 2023
e167678
Fix add-specials
Bike Sep 29, 2023
e872a95
Fix most of the stupid test failures for native
Bike Sep 29, 2023
3221ece
Fix setf function name lookup in compiler
Bike Sep 29, 2023
5f28580
Start on cross tester
Bike Sep 30, 2023
ed47da2
Define more stuff for cross tests sham
Bike Sep 30, 2023
a9e9cc9
port program error stuff to cross vm
Bike Sep 30, 2023
0a88749
fix setf sham for cross tester
Bike Sep 30, 2023
8358a7e
add test READMEs before I forget everything
Bike Sep 30, 2023
e87b34b
Move argument parsing errors to shared file
Bike Sep 30, 2023
08b4938
Link only in global environments
Bike Sep 30, 2023
f1247bb
Make MACROLET work regardless of environment
Bike Sep 30, 2023
5fae57e
Rewrite MACROLET tests to not use `
Bike Sep 30, 2023
dba861d
Fix special binding MACROLET tests
Bike Sep 30, 2023
62a7b59
Localize weird cl:compile usage
Bike Sep 30, 2023
dd8ab7a
Fix lambda list default form environments
Bike Sep 30, 2023
8c45d6d
Fix macrolet tests
Bike Sep 30, 2023
893b0f5
Fix overly special binding in optional/keyword parameters
Bike Sep 30, 2023
3870ea1
compiler: actually read from cells when necessary
Bike Sep 30, 2023
32ee5d0
cross VM: Fix NLX
Bike Sep 30, 2023
8a85b90
Dummy out CL:CATCH test for the moment
Bike Sep 30, 2023
dbc60d7
Skip ecclesia-broken macrolet tests, restore some others
Bike Oct 1, 2023
f9cc9d4
Automate tests on github
Bike Oct 1, 2023
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
66 changes: 66 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
name: Test

on:
workflow_dispatch:
push:
branches: [ main ]
pull_request:

jobs:
test:
name: ${{ matrix.host }} / ${{ matrix.mode }}

defaults:
run:
shell: bash -l {0}

strategy:
fail-fast: false
matrix:
host:
- sbcl # non-sbcl hosts would require more changes below
mode:
- native
- cross

runs-on: ubuntu-22.04

steps:
- name: Install SBCL
if: matrix.host == 'sbcl'
run: |
sudo apt-get update
sudo apt install -y sbcl

- name: Install Quicklisp
run: |
curl -kLO https://beta.quicklisp.org/quicklisp.lisp
sbcl --non-interactive --load quicklisp.lisp --eval "(quicklisp-quickstart:install)" --eval "(ql-util:without-prompting (ql:add-to-init-file))"

- name: Checkout repository
uses: actions/checkout@v4
with:
path: cvm

# Clostrum is not in Quicklisp as of now, so get it from github.

- name: Checkout Clostrum
uses: actions/checkout@v4
with:
repository: s-expressionists/Clostrum
path: Clostrum

- name: Configure ASDF to find everything
run: |
mkdir -p $HOME/.config/common-lisp/source-registry.conf.d
echo "(:TREE #P\"${{ github.workspace }}/\")" > $HOME/.config/common-lisp/source-registry.conf.d/cvm.conf

- name: Run native client tests
if: matrix.mode == 'native'
run: |
sbcl --load "${{ github.workspace }}/cvm/test/script.lisp"

- name: Run cross client tests
if: matrix.mode == 'cross'
run: |
sbcl --load "${{ github.workspace }}/cvm/test/cross/script.lisp"
86 changes: 57 additions & 29 deletions Cross/vm.lisp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
(defpackage #:cvm.cross.vm
(:use #:cl)
(:local-nicknames (#:m #:cvm.machine))
(:local-nicknames (#:m #:cvm.machine)
(#:arg #:cvm.argparse))
(:export #:initialize-vm)
(:export #:*trace*)
(:export #:symbol-cell))
Expand Down Expand Up @@ -106,13 +107,24 @@
(let ((cell (symbol-cell symbol global-cell)))
(setf (car cell) new)))

(defvar *dynenv* nil)
(define-condition out-of-extent-unwind (control-error)
())

(defun exit-to (vm entry-dynenv new-ip)
;; Make sure the entry is still on the DE stack.
;; If it is, reset the DE stack, and throw.
;; Otherwise complain.
(let ((old-de-stack (member entry-dynenv (vm-dynenv-stack vm))))
(when (null old-de-stack)
(error 'out-of-extent-unwind))
(setf (vm-dynenv-stack vm) old-de-stack)
(throw (entry-dynenv-tag entry-dynenv) new-ip)))

(defun instruction-trace (bytecode stack ip bp sp frame-size)
(fresh-line *trace-output*)
(let ((frame-end (+ bp frame-size))
;; skip package prefixes on inst names.
(*package* (find-package "CVM/MACHINE")))
(*package* (find-package "CVM.MACHINE")))
(prin1 (list (m:disassemble-instruction bytecode ip)
bp
sp
Expand Down Expand Up @@ -184,6 +196,13 @@
(error "Invalid bytecode: Reached end"))
(when trace
(instruction-trace bytecode stack ip bp sp frame-size))
;; The catch is for NLX. Without NLX, a (go loop) at the
;; bottom skips back up to the loop without setting IP.
;; When something NLXs to this frame, we throw the new IP
;; to the tag, set the IP, and then jump up to the loop.
;; We use CATCH instead of BLOCK on the theory that BLOCK
;; will have to allocate each loop, but well, I suspect
;; CATCH will too generally.
(setf ip
(catch tag
(ecase (code)
Expand Down Expand Up @@ -272,20 +291,23 @@
((#.m:check-arg-count-<=)
(let ((n (next-code)))
(unless (<= (vm-arg-count vm) n)
(error "Invalid number of arguments: Got ~d, need at most ~d."
(vm-arg-count vm) n)))
(error 'arg:wrong-number-of-arguments
:given-nargs (vm-arg-count vm)
:max-nargs n)))
(incf ip))
((#.m:check-arg-count->=)
(let ((n (next-code)))
(unless (>= (vm-arg-count vm) n)
(error "Invalid number of arguments: Got ~d, need at least ~d."
(vm-arg-count vm) n)))
(error 'arg:wrong-number-of-arguments
:given-nargs (vm-arg-count vm)
:min-nargs n)))
(incf ip))
((#.m:check-arg-count-=)
(let ((n (next-code)))
(unless (= (vm-arg-count vm) n)
(error "Invalid number of arguments: Got ~d, need exactly ~d."
(vm-arg-count vm) n)))
(error 'arg:wrong-number-of-arguments
:given-nargs (vm-arg-count vm)
:min-nargs n :max-nargs n)))
(incf ip))
((#.m:jump-if-supplied-8)
(incf ip (if (typep (stack (+ bp (next-code))) 'unbound-marker)
Expand Down Expand Up @@ -343,7 +365,7 @@
(key-literal-start (next-code))
(key-literal-end (+ key-literal-start key-count))
(key-frame-start (+ bp (next-code)))
(unknown-key-p nil)
(unknown-keys nil)
(allow-other-keys-p nil))
;; Initialize all key values to #<unbound-marker>
(loop for index from key-frame-start below (+ key-frame-start key-count)
Expand All @@ -353,30 +375,35 @@
((< arg-index more-start)
(cond ((= arg-index (1- more-start)))
((= arg-index (- more-start 2))
(error "Passed odd number of &KEY args!"))
(error 'arg:odd-keywords))
(t
(error "BUG! This can't happen!"))))
(let ((key (stack (1- arg-index))))
(if (eq key :allow-other-keys)
(setf allow-other-keys-p (stack arg-index))
(loop for key-index from key-literal-start
below key-literal-end
for offset of-type (unsigned-byte 16)
from key-frame-start
do (when (eq (constant key-index) key)
(setf (stack offset) (stack arg-index))
(return))
finally (setf unknown-key-p key))))))
(when (eq key :allow-other-keys)
(setf allow-other-keys-p (stack arg-index)))
(loop for key-index from key-literal-start
below key-literal-end
for offset of-type (unsigned-byte 16)
from key-frame-start
do (when (eq (constant key-index) key)
(setf (stack offset) (stack arg-index))
(return))
finally (unless (or allow-other-keys-p
(eq key :allow-other-keys))
(push key unknown-keys))))))
(when (and (not (or (logbitp 7 key-count-info)
allow-other-keys-p))
unknown-key-p)
(error "Unknown key arg ~a!" unknown-key-p)))
unknown-keys)
(error 'arg:unrecognized-keyword-argument
:unrecognized-keywords unknown-keys)))
(incf ip))
((#.m:save-sp)
(setf (stack (+ bp (next-code))) sp)
(setf (stack (+ bp (next-code)))
(list sp (vm-dynenv-stack vm)))
(incf ip))
((#.m:restore-sp)
(setf sp (stack (+ bp (next-code))))
(setf (values sp (vm-dynenv-stack vm))
(values-list (stack (+ bp (next-code)))))
(incf ip))
((#.m:entry)
(let ((de (make-entry-dynenv tag)))
Expand Down Expand Up @@ -415,13 +442,13 @@
(return))
((#.m:exit-8)
(incf ip (next-code-signed))
(throw (entry-dynenv-tag (spop)) ip))
(exit-to vm (spop) ip))
((#.m:exit-16)
(incf ip (next-code-signed-16))
(throw (entry-dynenv-tag (spop)) ip))
(exit-to vm (spop) ip))
((#.m:exit-24)
(incf ip (next-code-signed-24))
(throw (entry-dynenv-tag (spop)) ip))
(exit-to vm (spop) ip))
((#.m:entry-close)
(pop (vm-dynenv-stack vm))
(incf ip))
Expand Down Expand Up @@ -495,7 +522,8 @@
(#.m:const
(spush (constant (+ (next-code) (ash (next-code) 8))))
(incf ip)))))
(go loop)))))))
(go loop)))
(go loop)))))

(defmethod m:compute-instance-function ((client cvm.cross:client)
(closure m:bytecode-closure))
Expand Down
50 changes: 50 additions & 0 deletions arg-conditions.lisp
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
(defpackage #:cvm.argparse
(:use #:cl)
(:export #:argument-error
#:wrong-number-of-arguments #:odd-keywords
#:unrecognized-keyword-argument)
(:export #:parse-macro))

(in-package #:cvm.argparse)

;;; abstract parent type for errors signaled by lambda list processing
(define-condition argument-error (program-error)
((%called-function :initform nil :initarg :called-function
:reader called-function)))

;;; nabbed from clasp
(define-condition wrong-number-of-arguments (argument-error)
((%given-nargs :initarg :given-nargs :reader given-nargs)
(%min-nargs :initarg :min-nargs :reader min-nargs :initform nil)
(%max-nargs :initarg :max-nargs :reader max-nargs :initform nil))
(:report (lambda (condition stream)
(let* ((min (min-nargs condition))
(max (max-nargs condition))
;; FIXME: get an actual name if possible
(dname nil))
(format stream "~@[Calling ~a - ~]Got ~d arguments, but expected ~@?"
dname (given-nargs condition)
(cond ((null max) "at least ~d")
((null min) "at most ~*~d")
;; I think "exactly 0" is better than "at most 0", thus duplication
((= min max) "exactly ~d")
((zerop min) "at most ~*~d")
(t "between ~d and ~d"))
min max)))))

(define-condition odd-keywords (argument-error)
()
(:report (lambda (condition stream)
(format stream "Odd number of keyword arguments~:[~; for ~s~]."
(called-function condition)
;; FIXME: again, get an actual name somehow.
nil))))

(define-condition unrecognized-keyword-argument (argument-error)
((%unrecognized-keywords :initarg :unrecognized-keywords
:reader unrecognized-keywords))
(:report (lambda (condition stream)
(format stream "Unrecognized keyword arguments ~S~:[~; for ~S~]."
(unrecognized-keywords condition)
(called-function condition) ; FIXME: name
nil))))
11 changes: 6 additions & 5 deletions cmpltv.lisp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
(defpackage #:cvm.compile-file
(:use #:cl)
(:local-nicknames (#:cmp #:cvm.compile))
(:local-nicknames (#:cmp #:cvm.compile)
(#:arg #:cvm.argparse))
(:shadow #:compile-file #:macroexpand-1 #:macroexpand)
(:export #:with-constants
#:ensure-constant #:add-constant #:find-constant-index)
Expand Down Expand Up @@ -1263,13 +1264,13 @@
(bytecode-compile-toplevel-progn body new-env))))

(defun bytecode-compile-toplevel-macrolet (bindings body env)
(let ((macros nil))
(let ((macros nil)
(aenv (cmp:lexenv-for-macrolet env)))
(dolist (binding bindings)
(let* ((name (car binding)) (lambda-list (cadr binding))
(body (cddr binding))
(eform (trivial-cltl2:parse-macro name lambda-list body env))
(aenv (cmp:lexenv-for-macrolet env))
(expander (cmp:compile eform aenv))
(expander (cmp:compute-macroexpander
name lambda-list body aenv))
(info (cmp:make-local-macro name expander)))
(push (cons name info) macros)))
(bytecode-compile-toplevel-locally
Expand Down
Loading