Compare commits
3 Commits
refactor-t
...
8ae2346e41
| Author | SHA1 | Date | |
|---|---|---|---|
| 8ae2346e41 | |||
| 878d415e22 | |||
| c678df7978 |
16
Makefile
16
Makefile
@@ -49,12 +49,24 @@ fmt-c-writer.o: fmt-c-writer.module.scm fmt-c-writer.scm sex-fmt-c.o utils.o
|
|||||||
sexc.o: sexc.module.scm sexc.scm fmt-c-writer.o sex-macros.o sex-modules.o reader.o semen.o utils.o
|
sexc.o: sexc.module.scm sexc.scm fmt-c-writer.o sex-macros.o sex-modules.o reader.o semen.o utils.o
|
||||||
$(CHICKEN_C) $(CSC_FLAGS) $(MODULE_FLAGS) sexc.module.scm -o sexc.o -unit sexc -link fmt-c-writer,sex-macros,sex-modules,reader,semen,utils
|
$(CHICKEN_C) $(CSC_FLAGS) $(MODULE_FLAGS) sexc.module.scm -o sexc.o -unit sexc -link fmt-c-writer,sex-macros,sex-modules,reader,semen,utils
|
||||||
|
|
||||||
|
# Unit testing
|
||||||
sex-tests:
|
sex-tests:
|
||||||
$(MAKE) -C tests sex-tests
|
$(MAKE) -C ./tests sex-tests
|
||||||
cp ./tests/sex-tests ./
|
cp ./tests/sex-tests ./
|
||||||
|
|
||||||
|
sextest:
|
||||||
|
$(MAKE) -C ./tools/sextest sextest
|
||||||
|
cp ./tools/sextest/sextest .
|
||||||
|
|
||||||
|
SEX_TEST_PROGRAMS = hello-world lists
|
||||||
|
|
||||||
|
run-tests: sexc sex-tests sextest
|
||||||
|
./sex-tests && ./sextest --sexc=./sexc $(SEX_TEST_PROGRAMS:%=./tests/sex-programs/%.sex)
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f $(OBJ) main.o
|
rm -f $(OBJ) main.o
|
||||||
rm -f *.import.scm
|
rm -f *.import.scm
|
||||||
rm -f *.link
|
rm -f *.link
|
||||||
rm -f sexc sex-tests
|
rm -f sexc sex-tests sextest
|
||||||
|
|
||||||
|
.PHONY: clean run-tests
|
||||||
|
|||||||
13
reader.scm
13
reader.scm
@@ -22,19 +22,6 @@
|
|||||||
(with-input-from-file (pathname-strip-directory file)
|
(with-input-from-file (pathname-strip-directory file)
|
||||||
(fn (read-forms (list))))))
|
(fn (read-forms (list))))))
|
||||||
|
|
||||||
(define (read-bracket port)
|
|
||||||
(let loop ((c (read-char port))
|
|
||||||
(str (string)))
|
|
||||||
(cond ((char=? c #\])
|
|
||||||
(cons '¤
|
|
||||||
(with-input-from-string str
|
|
||||||
(fn (port-map identity read)))))
|
|
||||||
((char=? c #\[)
|
|
||||||
(loop port (conc )))
|
|
||||||
(else
|
|
||||||
(loop (read-char port)
|
|
||||||
(conc str c))))))
|
|
||||||
|
|
||||||
(define open-bracket-counter (make-parameter 0))
|
(define open-bracket-counter (make-parameter 0))
|
||||||
|
|
||||||
(define (read-raw-forms input-source)
|
(define (read-raw-forms input-source)
|
||||||
|
|||||||
4
sexc.scm
4
sexc.scm
@@ -155,7 +155,9 @@
|
|||||||
(return #f))
|
(return #f))
|
||||||
(load-persistent-module-paths)
|
(load-persistent-module-paths)
|
||||||
|
|
||||||
(sex-fmt-current-file (to-absolute-pathname input))
|
(if (eq? input 'stdin)
|
||||||
|
(sex-fmt-current-file "stdin")
|
||||||
|
(sex-fmt-current-file (to-absolute-pathname input)))
|
||||||
(let* ((raw-forms (append prelude (read-raw-forms input)))
|
(let* ((raw-forms (append prelude (read-raw-forms input)))
|
||||||
(sex-forms (semantic-process-forms raw-forms input)))
|
(sex-forms (semantic-process-forms raw-forms input)))
|
||||||
(if (or (get-arg args 'macro-expand #f)
|
(if (or (get-arg args 'macro-expand #f)
|
||||||
|
|||||||
13
tests/sex-programs/hello-world.sex
Normal file
13
tests/sex-programs/hello-world.sex
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
(input "Sextest")
|
||||||
|
(output "Hello from Sex!" "What is your name?" "Hello, Sextest!")
|
||||||
|
(return 255)
|
||||||
|
|
||||||
|
(include stdio.h)
|
||||||
|
|
||||||
|
(pub fn main ((argc int) (argv [* const char])) int
|
||||||
|
(puts "Hello from Sex!")
|
||||||
|
(var name [char 512])
|
||||||
|
(puts "What is your name?")
|
||||||
|
(scanf "%s" (cast (& name) (* char)))
|
||||||
|
(printf "Hello, %s!\n" name)
|
||||||
|
(return 255))
|
||||||
48
tests/sex-programs/list-macros.sex
Normal file
48
tests/sex-programs/list-macros.sex
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
(pub defmacro (list-T type)
|
||||||
|
(let ((list-type (cat 'list- type)))
|
||||||
|
`(struct ,list-type
|
||||||
|
((value ,type)
|
||||||
|
(next (* struct ,list-type))))))
|
||||||
|
|
||||||
|
(pub defmacro (make-list-T type is-public?)
|
||||||
|
(let ((list-type (list 'struct (cat 'list- type)))
|
||||||
|
(fn-name (cat 'make-list- type)))
|
||||||
|
`(,@(if is-public? '(pub) '()) fn ,fn-name () (* ,list-type)
|
||||||
|
(var list (* ,list-type) (cast (malloc (sizeof ,list-type)) (* ,list-type)))
|
||||||
|
(= (-> list next) NULL)
|
||||||
|
(return list))))
|
||||||
|
|
||||||
|
(pub defmacro (add-value-list-T type is-public?)
|
||||||
|
(let ((list-type (list 'struct (cat 'list- type)))
|
||||||
|
(fn-name (cat 'add-value-list- type)))
|
||||||
|
`(,@(if is-public? '(pub) '()) fn ,fn-name ((list * ,list-type) (value ,type)) void
|
||||||
|
(while (!= (-> list next) NULL)
|
||||||
|
(= list (-> list next)))
|
||||||
|
(= (-> list next) (,(cat 'make-list- type)))
|
||||||
|
(= (-> list value) value))))
|
||||||
|
|
||||||
|
(pub defmacro (length-list-T type is-public?)
|
||||||
|
(let ((fn-name (cat 'length-list- type))
|
||||||
|
(list-type (list 'struct (cat 'list- type))))
|
||||||
|
`(,@(if is-public? '(pub) '()) fn ,fn-name ((list ,(cons '* list-type))) size-t
|
||||||
|
(var n size-t 0)
|
||||||
|
(while (!= (-> list next) NULL)
|
||||||
|
(= list (-> list next))
|
||||||
|
(++ n))
|
||||||
|
(return n))))
|
||||||
|
|
||||||
|
(pub defmacro (is-empty-list-T type is-public?)
|
||||||
|
`(,@(if is-public? '(pub) '()) fn ,(cat 'is-empty-list- type)
|
||||||
|
((list ,(list '* 'struct (cat 'list- type))))
|
||||||
|
bool
|
||||||
|
(return (== (-> list next) NULL))))
|
||||||
|
|
||||||
|
(pub defmacro (list-for-each list-type list-var elt-type elt-var what-do)
|
||||||
|
(let ((list-var-2 (cat list-var '-2)))
|
||||||
|
`(begin
|
||||||
|
(var ,list-var-2 (* ,list-type) ,list-var)
|
||||||
|
(var ,elt-var ,elt-type (-> ,list-var-2 value))
|
||||||
|
(while (!= (-> ,list-var-2 next) NULL)
|
||||||
|
,what-do
|
||||||
|
(= ,list-var-2 (-> ,list-var-2 next))
|
||||||
|
(= ,elt-var (-> ,list-var-2 value))))))
|
||||||
50
tests/sex-programs/lists.sex
Normal file
50
tests/sex-programs/lists.sex
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
(input)
|
||||||
|
(output "Size of the list: 0"
|
||||||
|
"Size of the list: 2"
|
||||||
|
"3 4 "
|
||||||
|
"Size of the list: 2")
|
||||||
|
(return 0)
|
||||||
|
|
||||||
|
(include stdlib.h)
|
||||||
|
(include stddef.h)
|
||||||
|
(include stdio.h)
|
||||||
|
|
||||||
|
(import list-macros)
|
||||||
|
|
||||||
|
(struct foo
|
||||||
|
((a-field float)
|
||||||
|
(b int)
|
||||||
|
(c (* const char))
|
||||||
|
(not (fn ((val bool)) bool))))
|
||||||
|
|
||||||
|
(var f (struct foo))
|
||||||
|
|
||||||
|
(list-T int)
|
||||||
|
(make-list-T int #f)
|
||||||
|
(add-value-list-T int #f)
|
||||||
|
(length-list-T int #f)
|
||||||
|
(is-empty-list-T int #f)
|
||||||
|
|
||||||
|
(extern fn puk ((a int) (b float)) void)
|
||||||
|
(pub fn baz () bool
|
||||||
|
(return true))
|
||||||
|
|
||||||
|
(extern var i int)
|
||||||
|
(var j int)
|
||||||
|
(pub var k int)
|
||||||
|
|
||||||
|
(pub fn main () int
|
||||||
|
(var l (* struct list-int) (make-list-int))
|
||||||
|
(printf "Size of the list: %lu\n" (length-list-int l))
|
||||||
|
(add-value-list-int l 3)
|
||||||
|
(add-value-list-int l 4)
|
||||||
|
(printf "Size of the list: %lu\n" (length-list-int l))
|
||||||
|
(list-for-each (struct list-int) l int v
|
||||||
|
(printf "%d " v))
|
||||||
|
(printf "\n")
|
||||||
|
(printf "Size of the list: %lu\n" (length-list-int l))
|
||||||
|
(return 0))
|
||||||
|
|
||||||
|
(pub fn print-list ((l (* const struct list-int))) void
|
||||||
|
(list-for-each (const struct list-int) l int v (printf "%d " v))
|
||||||
|
(printf "\n"))
|
||||||
5
tools/sextest/Makefile
Normal file
5
tools/sextest/Makefile
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
CHICKEN_C = csc
|
||||||
|
CSC_FLAGS += -K prefix -static
|
||||||
|
|
||||||
|
sextest: sextest.scm
|
||||||
|
$(CHICKEN_C) $(CSC_FLAGS) sextest.scm -o sextest
|
||||||
26
tools/sextest/README.org
Normal file
26
tools/sextest/README.org
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
* Sextest
|
||||||
|
A tool for testing Sex compiler by using test programs.
|
||||||
|
The tools compiles test programs, then runs with provided
|
||||||
|
input, checking the output and return code.
|
||||||
|
|
||||||
|
* Test format
|
||||||
|
The test program is just a regular Sex program, which may contain
|
||||||
|
additional toplevel forms, to define compilation parameters, input to
|
||||||
|
the program, and expected output and return code. Default value for
|
||||||
|
compilation, input and output is an empty strings. For the return code
|
||||||
|
it is 0.
|
||||||
|
|
||||||
|
* Example
|
||||||
|
some-test.sex:
|
||||||
|
#+begin_src
|
||||||
|
(compilation "-- -O2")
|
||||||
|
(input "")
|
||||||
|
(output "Hello world!")
|
||||||
|
(return 123)
|
||||||
|
|
||||||
|
(include stdio.h)
|
||||||
|
|
||||||
|
(pub fn main () int
|
||||||
|
(puts "Hello World!")
|
||||||
|
(return 123))
|
||||||
|
#+end_src
|
||||||
13
tools/sextest/hello-sextest.sex
Normal file
13
tools/sextest/hello-sextest.sex
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
(input "Sextest")
|
||||||
|
(output "Hello from Sex!" "What is your name?" "Hello, Sextest!")
|
||||||
|
(return 255)
|
||||||
|
|
||||||
|
(include stdio.h)
|
||||||
|
|
||||||
|
(pub fn main ((argc int) (argv [* const char])) int
|
||||||
|
(puts "Hello from Sex!")
|
||||||
|
(var name [char 512])
|
||||||
|
(puts "What is your name?")
|
||||||
|
(scanf "%s" (cast (& name) (* char)))
|
||||||
|
(printf "Hello, %s!\n" name)
|
||||||
|
(return 255))
|
||||||
211
tools/sextest/sextest.scm
Normal file
211
tools/sextest/sextest.scm
Normal file
@@ -0,0 +1,211 @@
|
|||||||
|
(import scheme
|
||||||
|
brev-separate
|
||||||
|
(chicken base)
|
||||||
|
(chicken file)
|
||||||
|
(chicken io)
|
||||||
|
(chicken pathname)
|
||||||
|
(chicken port)
|
||||||
|
(chicken process)
|
||||||
|
(chicken process-context)
|
||||||
|
(chicken read-syntax)
|
||||||
|
(chicken syntax)
|
||||||
|
fmt
|
||||||
|
getopt-long
|
||||||
|
srfi-1)
|
||||||
|
|
||||||
|
(define-syntax prog1
|
||||||
|
(syntax-rules ()
|
||||||
|
((prog1 form . forms)
|
||||||
|
(let ((res form))
|
||||||
|
(begin . forms)
|
||||||
|
res))))
|
||||||
|
|
||||||
|
(define-syntax with-directory
|
||||||
|
(syntax-rules ()
|
||||||
|
((with-directory path form . forms)
|
||||||
|
(let ((current-dir (current-directory)))
|
||||||
|
(set-working-directory path)
|
||||||
|
(prog1
|
||||||
|
(begin form . forms)
|
||||||
|
(change-directory current-dir))))))
|
||||||
|
|
||||||
|
(define (set-working-directory file)
|
||||||
|
(change-directory
|
||||||
|
(normalize-pathname
|
||||||
|
(if (absolute-pathname? file)
|
||||||
|
(pathname-directory file)
|
||||||
|
(make-absolute-pathname
|
||||||
|
(current-directory)
|
||||||
|
(pathname-directory file))))))
|
||||||
|
|
||||||
|
;;; TODO: use sexc reader code i.e. link with sex reader
|
||||||
|
(define open-bracket-counter (make-parameter 0))
|
||||||
|
|
||||||
|
(define (read-raw-forms input-source)
|
||||||
|
(let ((bracket-end (gensym)))
|
||||||
|
(set-read-syntax!
|
||||||
|
#\]
|
||||||
|
(lambda (port)
|
||||||
|
(when (= 0 (open-bracket-counter))
|
||||||
|
(error "Unmatched closing bracket"))
|
||||||
|
(open-bracket-counter (- (open-bracket-counter) 1))
|
||||||
|
bracket-end))
|
||||||
|
|
||||||
|
(set-read-syntax!
|
||||||
|
#\[
|
||||||
|
(lambda (port)
|
||||||
|
(open-bracket-counter (+ (open-bracket-counter) 1))
|
||||||
|
(let loop ((r (read port))
|
||||||
|
(acc (list)))
|
||||||
|
(if (eq? r bracket-end)
|
||||||
|
(cons '¤ (reverse acc))
|
||||||
|
(loop (read port)
|
||||||
|
(cons r acc)))))))
|
||||||
|
(read-from-file input-source))
|
||||||
|
|
||||||
|
(define (read-from-file file)
|
||||||
|
(with-directory file
|
||||||
|
(with-input-from-file (pathname-strip-directory file)
|
||||||
|
(fn (read-forms (list))))))
|
||||||
|
|
||||||
|
(define (read-forms acc)
|
||||||
|
(let ((r (read-with-source-info (current-input-port))))
|
||||||
|
(if (eof-object? r) (reverse acc)
|
||||||
|
(read-forms (cons r acc)))))
|
||||||
|
|
||||||
|
(define (print-help)
|
||||||
|
(fmt #t "Usage: sextest [options] filename" nl
|
||||||
|
"Options:" nl
|
||||||
|
(usage opts-grammar) nl))
|
||||||
|
|
||||||
|
(define (process-file target-path)
|
||||||
|
(let ((contents (read-raw-forms target-path)))
|
||||||
|
(foldl (lambda (acc elt)
|
||||||
|
(case (car elt)
|
||||||
|
((compilation input output return)
|
||||||
|
(cons
|
||||||
|
(append (car acc) (list elt))
|
||||||
|
(cdr acc)))
|
||||||
|
(else
|
||||||
|
(cons
|
||||||
|
(car acc)
|
||||||
|
(append (cdr acc) (list elt))))))
|
||||||
|
(cons (list) (list))
|
||||||
|
contents)))
|
||||||
|
|
||||||
|
(define (compile src flags sexc)
|
||||||
|
(let ((compiler (or
|
||||||
|
(and sexc (cdr sexc))
|
||||||
|
(get-environment-variable "SEXC")
|
||||||
|
"sexc"))
|
||||||
|
(compiled-file (create-temporary-file)))
|
||||||
|
(call-with-values
|
||||||
|
(fn
|
||||||
|
(process compiler
|
||||||
|
(append (list "-o" compiled-file)
|
||||||
|
flags)))
|
||||||
|
(lambda (out-port in-port pid)
|
||||||
|
(with-output-to-port in-port
|
||||||
|
(fn (map (fn (fmt #t x)) src)))
|
||||||
|
(close-output-port in-port)
|
||||||
|
|
||||||
|
(call-with-values
|
||||||
|
(fn (process-wait pid))
|
||||||
|
(lambda (pid exited retcode)
|
||||||
|
(if (= 0 retcode)
|
||||||
|
compiled-file
|
||||||
|
#f)))))))
|
||||||
|
|
||||||
|
(define (run-and-check file in out ret)
|
||||||
|
(call-with-values
|
||||||
|
(fn (process file))
|
||||||
|
(lambda (out-port in-port pid)
|
||||||
|
(when in
|
||||||
|
(with-output-to-port in-port
|
||||||
|
(fn (map (fn (fmt #t x))
|
||||||
|
(cdr in))))
|
||||||
|
(close-output-port in-port))
|
||||||
|
(let ((out-lines
|
||||||
|
(with-input-from-port out-port
|
||||||
|
(fn
|
||||||
|
(let loop ((line (read-line))
|
||||||
|
(lines (list)))
|
||||||
|
(if (eof-object? line)
|
||||||
|
(reverse lines)
|
||||||
|
(loop (read-line)
|
||||||
|
(cons line lines)))))))
|
||||||
|
(ret-code
|
||||||
|
(call-with-values
|
||||||
|
;; TODO: what if the program hangs
|
||||||
|
;; we need some kind of timeout mechanism
|
||||||
|
(fn
|
||||||
|
(process-wait pid))
|
||||||
|
(lambda (pid exited retcode)
|
||||||
|
retcode))))
|
||||||
|
(and
|
||||||
|
(if (not (= ret-code (cadr ret)))
|
||||||
|
(begin
|
||||||
|
(fmt #t "Retcode differs. Got " ret-code ", expected " (cadr ret) nl)
|
||||||
|
#f)
|
||||||
|
#t)
|
||||||
|
|
||||||
|
(if (not (equal? out-lines (cdr out)))
|
||||||
|
(begin
|
||||||
|
(fmt #t "Output differs. Got " out-lines " expected " (cdr out) nl)
|
||||||
|
#f)
|
||||||
|
#t))))))
|
||||||
|
|
||||||
|
(define opts-grammar
|
||||||
|
`((sexc ,(fmt #f "Path to sexc compiler. Defaults to value of SEXC" nl
|
||||||
|
(pad 26) "environment variable, ot if it's empty, to sexc" nl )
|
||||||
|
(required #f)
|
||||||
|
(value #t))
|
||||||
|
(help "Show this help"
|
||||||
|
(required #f)
|
||||||
|
(value #f)
|
||||||
|
(single-char #\h))))
|
||||||
|
|
||||||
|
(define (process-test-file sexc path)
|
||||||
|
(set-environment-variable! "SEX_MODULE_PATH"
|
||||||
|
(normalize-pathname (make-absolute-pathname
|
||||||
|
(current-directory)
|
||||||
|
(pathname-directory path))))
|
||||||
|
(let* ((settings-and-src (process-file path))
|
||||||
|
(settings (car settings-and-src))
|
||||||
|
(src (cdr settings-and-src))
|
||||||
|
(compiled-file (compile src (assoc 'compile settings) sexc)))
|
||||||
|
(if (not compiled-file)
|
||||||
|
(begin (fmt #t "Failed to compile " path nl)
|
||||||
|
#f)
|
||||||
|
(if (run-and-check
|
||||||
|
compiled-file
|
||||||
|
(assoc 'input settings)
|
||||||
|
(assoc 'output settings)
|
||||||
|
(assoc 'return settings))
|
||||||
|
(begin (fmt #t ".")
|
||||||
|
#t)
|
||||||
|
(begin (fmt #t ",")
|
||||||
|
#f)))))
|
||||||
|
|
||||||
|
(define (main)
|
||||||
|
(let ((args (getopt-long (command-line-arguments)
|
||||||
|
opts-grammar)))
|
||||||
|
(when (assoc 'help args)
|
||||||
|
(print-help)
|
||||||
|
(exit 0))
|
||||||
|
(when (null? (cdr (assoc '@ args)))
|
||||||
|
(fmt #t "Missing target file" nl)
|
||||||
|
(print-help)
|
||||||
|
(exit 1))
|
||||||
|
(unless
|
||||||
|
(foldl and
|
||||||
|
#t
|
||||||
|
(map (fn (process-test-file (assoc 'sexc args) x))
|
||||||
|
(cdr (assoc '@ args))))
|
||||||
|
;; TODO: add more verbose and human readable output and reporting
|
||||||
|
(fmt #t nl)
|
||||||
|
(exit 2))
|
||||||
|
(fmt #t nl)
|
||||||
|
(exit 0)))
|
||||||
|
|
||||||
|
(main)
|
||||||
Reference in New Issue
Block a user