Compare commits
2 Commits
7356a5000a
...
7f3798a9c6
| Author | SHA1 | Date | |
|---|---|---|---|
| 7f3798a9c6 | |||
| d850b0dadf |
@@ -1,11 +1,8 @@
|
||||
# Fudge-chez
|
||||
This is the Fudge programming language implemented in Chez scheme.
|
||||
This is the Fudge programming language implemented in r7rs-scheme.
|
||||
For the original project, go to Wannie's
|
||||
[repository](https://shit-co.de/wanniepannie/fudge2.1).
|
||||
|
||||
# Installation
|
||||
To run fudge-chez, install [Chez](https://scheme.com) and run the
|
||||
program with ```chez --program fudge-chez.ss```
|
||||
|
||||
## Why Chez scheme?
|
||||
Because Scheme is elegant. (In theory.)
|
||||
To run fudge-chez, install a r7rs-compliant scheme implementation
|
||||
and execute the script fudge.ss.
|
||||
|
||||
101
fudge-chez.ss
101
fudge-chez.ss
@@ -1,101 +0,0 @@
|
||||
(import (rnrs))
|
||||
|
||||
(define get-word
|
||||
(lambda (file)
|
||||
(let ([c (lookahead-char file)])
|
||||
(cond
|
||||
[(eof-object? c) ""]
|
||||
[(char-alphabetic? c)
|
||||
(get-char file)
|
||||
(string-append (string c) (get-word file))]
|
||||
[else ""]))))
|
||||
|
||||
(define char->digit
|
||||
(lambda (c)
|
||||
(- (char->integer c) (char->integer #\0))))
|
||||
|
||||
; get-number supports only nonnegative integers.
|
||||
(define get-number
|
||||
(lambda (file)
|
||||
(let f ([total 0])
|
||||
(let ([c (lookahead-char file)])
|
||||
(if (char-numeric? c)
|
||||
(begin
|
||||
(get-char file)
|
||||
(f (+ (* total 10) (char->digit c))))
|
||||
total)))))
|
||||
|
||||
(define get-token
|
||||
(lambda (file)
|
||||
(let ([c (lookahead-char file)])
|
||||
(cond
|
||||
[(eof-object? c) 'end-of-file]
|
||||
[(char-whitespace? c)
|
||||
(get-char file)
|
||||
(get-token file)]
|
||||
[(char-alphabetic? c)
|
||||
(get-word file)]
|
||||
[(char-numeric? c)
|
||||
(get-number file)]
|
||||
[(eq? c #\+) (get-char file) '+]
|
||||
[(eq? c #\-) (get-char file) '-]
|
||||
[(eq? c #\*) (get-char file) '*]
|
||||
[(eq? c #\/) (get-char file) '/]
|
||||
[(eq? c #\=) (get-char file) #\=]
|
||||
[else (error 'get-token "Bad character" c)]))))
|
||||
|
||||
(define get-tokens
|
||||
(lambda (file)
|
||||
(let ([token (get-token file)])
|
||||
(if (eq? token 'end-of-file)
|
||||
'()
|
||||
(cons token (get-tokens file))))))
|
||||
|
||||
(define tokenize
|
||||
(lambda (filename)
|
||||
(let ([file (open-input-file filename)])
|
||||
(get-tokens file))))
|
||||
|
||||
(define test-lexer-fail
|
||||
(lambda (input want got)
|
||||
(display "text-lexer-fail: input=")
|
||||
(write input)
|
||||
(display "; want: ")
|
||||
(write want)
|
||||
(display "; got: ")
|
||||
(write got)
|
||||
(display ".")
|
||||
(newline)))
|
||||
|
||||
(define test-lexer-success
|
||||
(lambda (input got)
|
||||
(display "text-lexer-success: input=")
|
||||
(write input)
|
||||
(display "; got: ")
|
||||
(write got)
|
||||
(display ".")
|
||||
(newline)))
|
||||
|
||||
(define test-lexer
|
||||
(lambda (input want)
|
||||
(let ([port (open-string-input-port input)])
|
||||
(call/cc
|
||||
(lambda (i-got-exception)
|
||||
(with-exception-handler
|
||||
(lambda (x)
|
||||
(display "test-lexer-fail: input ")
|
||||
(write input)
|
||||
(display " throws ")
|
||||
(write x)
|
||||
(display ".")
|
||||
(newline)
|
||||
(i-got-exception x))
|
||||
(lambda ()
|
||||
(let ([got (get-tokens port)])
|
||||
(if (equal? got want)
|
||||
(test-lexer-success input got)
|
||||
(test-lexer-fail input want got))))))))))
|
||||
|
||||
(test-lexer "hello world" '("hello" "world"))
|
||||
(test-lexer "+ * / -" '(+ * / -))
|
||||
(test-lexer "identifier = 14" '("identifier" = 14))
|
||||
140
fudge.ss
Executable file
140
fudge.ss
Executable file
@@ -0,0 +1,140 @@
|
||||
(import (scheme base)
|
||||
(scheme file)
|
||||
(scheme write)
|
||||
(scheme char))
|
||||
|
||||
(define-syntax import-scheme
|
||||
(syntax-rules ()
|
||||
((_ module ...)
|
||||
(import (scheme module) ...))))
|
||||
|
||||
(define keywords
|
||||
'("true" "false" "struct" "enum" "if" "then" "else" "type" "let"))
|
||||
|
||||
(define keyword?
|
||||
(lambda (word)
|
||||
(member word keywords)))
|
||||
|
||||
(define get-word-string
|
||||
(lambda (file)
|
||||
(let ((c (peek-char file)))
|
||||
(cond
|
||||
((eof-object? c) "")
|
||||
((char-alphabetic? c)
|
||||
(read-char file)
|
||||
(string-append (string c) (get-word file)))
|
||||
(else "")))))
|
||||
|
||||
(define get-word
|
||||
(lambda (file)
|
||||
(let ((word (get-word-string file)))
|
||||
(if (keyword? word)
|
||||
(string->symbol word)
|
||||
word))))
|
||||
|
||||
(define char->digit
|
||||
(lambda (c)
|
||||
(- (char->integer c) (char->integer #\0))))
|
||||
|
||||
; get-number supports only nonnegative integers.
|
||||
(define get-number
|
||||
(lambda (file)
|
||||
(let f ((total 0))
|
||||
(let ((c (peek-char file)))
|
||||
(cond
|
||||
((eof-object? c) total)
|
||||
((char-numeric? c)
|
||||
(read-char file)
|
||||
(f (+ (* total 10) (char->digit c))))
|
||||
(else total))))))
|
||||
|
||||
(define get-token
|
||||
(lambda (file)
|
||||
(let ((c (peek-char file)))
|
||||
(cond
|
||||
((eof-object? c) 'end-of-file)
|
||||
((char-whitespace? c)
|
||||
(read-char file)
|
||||
(get-token file))
|
||||
((char-alphabetic? c)
|
||||
(get-word file))
|
||||
((char-numeric? c)
|
||||
(get-number file))
|
||||
((eq? c #\+) (read-char file) '+)
|
||||
((eq? c #\-) (read-char file) '-)
|
||||
((eq? c #\*) (read-char file) '*)
|
||||
((eq? c #\/) (read-char file) '/)
|
||||
((eq? c #\=) (read-char file) '=)
|
||||
((eq? c #\() (read-char file) 'left-parenthesis)
|
||||
((eq? c #\)) (read-char file) 'right-parenthesis)
|
||||
((eq? c #\{) (read-char file) 'left-brace)
|
||||
((eq? c #\}) (read-char file) 'right-brace)
|
||||
((eq? c #\;) (read-char file) 'semicolon)
|
||||
((eq? c #\:) (read-char file) 'colon)
|
||||
(else (error 'get-token "Bad character" c))))))
|
||||
|
||||
(define get-tokens
|
||||
(lambda (file)
|
||||
(let ((token (get-token file)))
|
||||
(if (eq? token 'end-of-file)
|
||||
'()
|
||||
(cons token (get-tokens file))))))
|
||||
|
||||
(define tokenize
|
||||
(lambda (filename)
|
||||
(let ((file (open-input-file filename)))
|
||||
(get-tokens file))))
|
||||
|
||||
(define test-lexer-fail
|
||||
(lambda (input want got)
|
||||
(display "text-lexer-fail: input=")
|
||||
(write input)
|
||||
(display "; want: ")
|
||||
(write want)
|
||||
(display "; got: ")
|
||||
(write got)
|
||||
(display ".")
|
||||
(newline)))
|
||||
|
||||
|
||||
(define test-lexer-success
|
||||
(lambda (input got)
|
||||
(display "text-lexer-success: input=")
|
||||
(write input)
|
||||
(display "; got: ")
|
||||
(write got)
|
||||
(display ".")
|
||||
(newline)))
|
||||
|
||||
(define test-lexer-fail-exception
|
||||
(lambda (input x)
|
||||
(display "test-lexer-fail: input ")
|
||||
(write input)
|
||||
(display " throws ")
|
||||
(write (error-object-message x))
|
||||
(display ".")
|
||||
(newline)))
|
||||
|
||||
(define test-lexer
|
||||
(lambda (input want)
|
||||
(let ((port (open-input-string input)))
|
||||
(call/cc
|
||||
(lambda (i-got-exception)
|
||||
(with-exception-handler
|
||||
(lambda (x)
|
||||
(test-lexer-fail-exception input x)
|
||||
(i-got-exception x))
|
||||
(lambda ()
|
||||
(let ((got (get-tokens port)))
|
||||
(if (equal? got want)
|
||||
(test-lexer-success input got)
|
||||
(test-lexer-fail input want got))))))))))
|
||||
|
||||
(test-lexer "hello world" '("hello" "world"))
|
||||
(test-lexer "+ * / - = " '(+ * / - =))
|
||||
(test-lexer "( ) { }" '(left-parenthesis right-parenthesis left-brace right-brace))
|
||||
(test-lexer "true false" '(true false))
|
||||
(test-lexer "if then else" '(if then else))
|
||||
(test-lexer ": ;" '(colon semicolon))
|
||||
(test-lexer "identifier = 14" '("identifier" = 14))
|
||||
(test-lexer "" '())
|
||||
Reference in New Issue
Block a user