2005-08-23 15:02:00 -04:00
|
|
|
IN: infix
|
2006-01-24 21:52:17 -05:00
|
|
|
USING: arrays errors generic hashtables io kernel kernel-internals lists math math-contrib namespaces parser parser-combinators prettyprint sequences strings vectors words ;
|
|
|
|
|
|
|
|
: 2list ( x y -- [ x y ] ) f cons cons ;
|
2005-08-23 14:43:12 -04:00
|
|
|
|
|
|
|
! Tokenizer
|
|
|
|
|
|
|
|
TUPLE: tok char ;
|
|
|
|
|
|
|
|
TUPLE: brackets seq ender ;
|
|
|
|
|
2005-08-25 18:02:30 -04:00
|
|
|
SYMBOL: apostrophe
|
2005-08-23 14:43:12 -04:00
|
|
|
|
|
|
|
SYMBOL: code #! Source code
|
|
|
|
SYMBOL: spot #! Current index of string
|
|
|
|
|
|
|
|
: take-until ( quot -- parsed-stuff | quot: char -- ? )
|
|
|
|
#! Take the substring of a string starting at spot
|
|
|
|
#! from code until the quotation given is true and
|
|
|
|
#! advance spot to after the substring.
|
|
|
|
>r spot get code get 2dup r>
|
|
|
|
skip [ swap subseq ] keep
|
|
|
|
spot set ;
|
|
|
|
|
|
|
|
: parse-blank ( -- )
|
|
|
|
#! Advance code past any whitespace, including newlines
|
|
|
|
spot get code get [ blank? not ] skip spot set ;
|
|
|
|
|
|
|
|
: not-done? ( -- ? )
|
|
|
|
#! Return t if spot is not at the end of code
|
|
|
|
code get length spot get = not ;
|
|
|
|
|
|
|
|
: incr-spot ( -- )
|
|
|
|
#! Increment spot.
|
|
|
|
spot [ 1 + ] change ;
|
|
|
|
|
|
|
|
: parse-var ( -- variable-name )
|
|
|
|
#! Take a series of letters from code, advancing
|
|
|
|
#! spot and returning the letters.
|
|
|
|
[ letter? not ] take-until ;
|
|
|
|
|
|
|
|
: parse-num ( -- number )
|
|
|
|
#! Take a number from code, advancing spot and
|
|
|
|
#! returning the number.
|
2005-08-25 18:02:30 -04:00
|
|
|
[ "0123456789." member? not ] take-until string>number ;
|
2005-08-23 14:43:12 -04:00
|
|
|
|
|
|
|
: get-token ( -- char )
|
|
|
|
spot get code get nth ;
|
|
|
|
|
2005-08-25 18:02:30 -04:00
|
|
|
DEFER: token
|
|
|
|
|
2005-08-23 14:43:12 -04:00
|
|
|
: next-token ( list -- list )
|
|
|
|
#! Take one token from code and return it
|
|
|
|
parse-blank not-done? [
|
|
|
|
get-token token
|
|
|
|
] when ;
|
|
|
|
|
2005-08-25 18:02:30 -04:00
|
|
|
: token
|
|
|
|
{
|
|
|
|
{ [ dup letter? ] [ drop parse-var swons ] }
|
|
|
|
{ [ dup "0123456789." member? ] [ drop parse-num swons ] }
|
|
|
|
{ [ dup ";!@#$%^&*?/|\\=+_-~" member? ] [ <tok> swons incr-spot ] }
|
|
|
|
{ [ dup "([{" member? ] [ drop f incr-spot ] }
|
|
|
|
{ [ dup ")]}" member? ] [ <brackets> swons incr-spot ] }
|
|
|
|
{ [ dup CHAR: ' = ] [ drop apostrophe swons incr-spot ] }
|
|
|
|
{ [ t ] [ "Bad character " swap ch>string append throw ] }
|
|
|
|
} cond next-token ;
|
2005-08-23 14:43:12 -04:00
|
|
|
|
|
|
|
: tokenize ( string -- tokens )
|
|
|
|
#! Tokenize a string, returning a list of tokens
|
|
|
|
[
|
|
|
|
code set 0 spot set
|
|
|
|
f next-token reverse
|
|
|
|
] with-scope ;
|
|
|
|
|
|
|
|
|
|
|
|
! Parser
|
|
|
|
|
|
|
|
TUPLE: apply func args ;
|
|
|
|
#! Function application
|
|
|
|
C: apply
|
|
|
|
>r [ ] subset r>
|
|
|
|
[ set-apply-args ] keep
|
|
|
|
[ set-apply-func ] keep ;
|
|
|
|
|
|
|
|
UNION: value number string ;
|
|
|
|
|
|
|
|
: semicolon ( -- semicolon )
|
|
|
|
#! The semicolon token
|
2005-10-29 23:25:38 -04:00
|
|
|
T{ tok f CHAR: ; } ;
|
2005-08-23 14:43:12 -04:00
|
|
|
|
|
|
|
: nest-apply ( [ ast ] -- apply )
|
|
|
|
unswons unit swap [
|
|
|
|
swap <apply> unit
|
|
|
|
] each car ;
|
|
|
|
|
|
|
|
GENERIC: parse-token ( ast tokens token -- ast tokens )
|
|
|
|
#! Take one or more tokens
|
|
|
|
|
|
|
|
DEFER: parse-tokens
|
|
|
|
|
|
|
|
: semicolon-split ( list -- [ ast ] )
|
|
|
|
reverse semicolon unit split [ parse-tokens ] map ;
|
|
|
|
|
|
|
|
M: value parse-token
|
|
|
|
swapd swons swap ;
|
|
|
|
|
|
|
|
M: brackets parse-token
|
2005-08-25 18:02:30 -04:00
|
|
|
swapd dup brackets-seq swap brackets-ender {
|
|
|
|
{ [ dup CHAR: ] = ] [ drop semicolon-split >r unswons r> <apply> swons ] }
|
|
|
|
{ [ dup CHAR: } = ] [ drop semicolon-split >vector swons ] }
|
|
|
|
{ [ CHAR: ) = ] [ reverse parse-tokens swons ] }
|
|
|
|
} cond swap ;
|
2005-08-23 14:43:12 -04:00
|
|
|
|
|
|
|
M: object tok-char drop -1 ; ! Hack!
|
|
|
|
|
|
|
|
GENERIC: tok>string ( token/string -- string )
|
|
|
|
M: tok tok>string
|
|
|
|
tok-char ch>string ;
|
|
|
|
M: string tok>string ;
|
|
|
|
|
|
|
|
: binary-op ( ast tokens token -- ast )
|
|
|
|
>r >r unswons r> parse-tokens 2list r>
|
|
|
|
tok>string swap <apply> swons ;
|
|
|
|
|
|
|
|
: unary-op ( ast tokens token -- ast )
|
|
|
|
tok>string -rot nip
|
|
|
|
parse-tokens unit <apply> unit ;
|
|
|
|
|
2005-08-25 18:02:30 -04:00
|
|
|
: null-op ( ast tokens token -- ast )
|
2005-08-23 14:43:12 -04:00
|
|
|
nip tok-char ch>string swons ;
|
|
|
|
|
2005-08-25 18:02:30 -04:00
|
|
|
M: tok parse-token
|
2005-08-23 14:43:12 -04:00
|
|
|
over [
|
|
|
|
pick [
|
|
|
|
binary-op
|
|
|
|
] [
|
|
|
|
unary-op
|
2006-01-24 21:52:17 -05:00
|
|
|
] if
|
2005-08-23 14:43:12 -04:00
|
|
|
] [
|
2005-08-25 18:02:30 -04:00
|
|
|
null-op
|
2006-01-24 21:52:17 -05:00
|
|
|
] if f ;
|
2005-08-23 14:43:12 -04:00
|
|
|
|
2005-08-25 18:02:30 -04:00
|
|
|
( ast tokens token -- ast tokens )
|
|
|
|
|
|
|
|
M: symbol parse-token ! apostrophe
|
|
|
|
drop unswons >r parse-tokens >r unswons r> 2list r>
|
2005-08-23 14:43:12 -04:00
|
|
|
unit parse-tokens swap <apply> swons f ;
|
|
|
|
|
|
|
|
: (parse-tokens) ( ast tokens -- ast )
|
|
|
|
dup [
|
|
|
|
unswons parse-token (parse-tokens)
|
|
|
|
] [
|
|
|
|
drop
|
2006-01-24 21:52:17 -05:00
|
|
|
] if ;
|
2005-08-23 14:43:12 -04:00
|
|
|
|
|
|
|
: parse-tokens ( tokens -- ast )
|
|
|
|
#! Convert a list of tokens into an AST
|
|
|
|
f swap (parse-tokens) nest-apply ;
|
|
|
|
|
|
|
|
: parse-full ( string -- ast )
|
|
|
|
#! Convert a string into an AST
|
|
|
|
tokenize parse-tokens ;
|
|
|
|
|
|
|
|
|
|
|
|
! Compiler
|
|
|
|
|
|
|
|
GENERIC: compile-ast ( vars ast -- quot )
|
|
|
|
|
|
|
|
M: string compile-ast ! variables
|
|
|
|
swap index dup -1 = [
|
|
|
|
"Variable not found" throw
|
|
|
|
] [
|
|
|
|
[ swap array-nth ] cons
|
2006-01-24 21:52:17 -05:00
|
|
|
] if ;
|
2005-08-23 14:43:12 -04:00
|
|
|
|
|
|
|
: replace-with ( data -- [ drop data ] )
|
|
|
|
\ drop swap 2list ;
|
|
|
|
|
|
|
|
UNION: comp-literal number general-list ;
|
|
|
|
|
|
|
|
M: comp-literal compile-ast ! literal numbers
|
|
|
|
replace-with nip ;
|
|
|
|
|
2005-08-25 18:02:30 -04:00
|
|
|
: accumulator ( vars { asts } quot -- quot )
|
2005-08-23 14:43:12 -04:00
|
|
|
-rot [
|
|
|
|
[
|
|
|
|
\ dup ,
|
|
|
|
compile-ast %
|
|
|
|
dup %
|
|
|
|
] each-with
|
2005-09-01 16:07:22 -04:00
|
|
|
] [ ] make nip ;
|
2005-08-23 14:43:12 -04:00
|
|
|
|
|
|
|
M: vector compile-ast ! literal vectors
|
2005-08-30 14:53:23 -04:00
|
|
|
dup [ number? ] all? [
|
2005-08-23 14:43:12 -04:00
|
|
|
replace-with nip
|
|
|
|
] [
|
2005-09-01 16:07:22 -04:00
|
|
|
[ , ] accumulator [ { } make nip ] cons
|
2006-01-24 21:52:17 -05:00
|
|
|
] if ;
|
2005-08-23 14:43:12 -04:00
|
|
|
|
|
|
|
: infix-relation
|
|
|
|
#! Wraps operators like = and > so that if they're given
|
|
|
|
#! f as either argument, they return f, and they return f if
|
|
|
|
#! the operation yields f, but if it yields t, it returns the
|
|
|
|
#! left argument. This way, these types of operations can be
|
|
|
|
#! composed.
|
|
|
|
>r 2dup and not [
|
|
|
|
r> 3drop f
|
|
|
|
] [
|
|
|
|
dupd r> call [
|
|
|
|
drop f
|
|
|
|
] unless
|
2006-01-24 21:52:17 -05:00
|
|
|
] if ;
|
2005-08-23 14:43:12 -04:00
|
|
|
|
|
|
|
: functions
|
|
|
|
#! Regular functions
|
|
|
|
#! Gives quotation applicable to stack
|
2005-10-29 23:25:38 -04:00
|
|
|
H{
|
2005-08-23 14:43:12 -04:00
|
|
|
[ [[ "+" 2 ]] + ]
|
|
|
|
[ [[ "-" 2 ]] - ]
|
|
|
|
[ [[ ">" 2 ]] [ > ] infix-relation ]
|
|
|
|
[ [[ "<" 2 ]] [ < ] infix-relation ]
|
|
|
|
[ [[ "=" 2 ]] [ = ] infix-relation ]
|
|
|
|
[ [[ "-" 1 ]] neg ]
|
|
|
|
[ [[ "~" 1 ]] not ]
|
|
|
|
[ [[ "&" 2 ]] and ]
|
|
|
|
[ [[ "|" 2 ]] or ]
|
2005-08-25 18:02:30 -04:00
|
|
|
[ [[ "&" 1 ]] t [ and ] reduce ]
|
|
|
|
[ [[ "|" 1 ]] f [ or ] reduce ]
|
2005-08-23 14:43:12 -04:00
|
|
|
[ [[ "*" 2 ]] * ]
|
2005-08-25 18:02:30 -04:00
|
|
|
[ [[ "ln" 1 ]] log ]
|
2005-08-23 14:43:12 -04:00
|
|
|
[ [[ "plusmin" 2 ]] [ + ] 2keep - ]
|
|
|
|
[ [[ "@" 2 ]] swap nth ]
|
|
|
|
[ [[ "sqrt" 1 ]] sqrt ]
|
|
|
|
[ [[ "/" 2 ]] / ]
|
|
|
|
[ [[ "^" 2 ]] ^ ]
|
2005-08-25 18:02:30 -04:00
|
|
|
[ [[ "#" 1 ]] length ]
|
|
|
|
[ [[ "eq" 2 ]] eq? ]
|
|
|
|
[ [[ "*" 1 ]] first ]
|
|
|
|
[ [[ "+" 1 ]] flip ]
|
|
|
|
[ [[ "\\" 1 ]] <reversed> ]
|
|
|
|
[ [[ "sin" 1 ]] sin ]
|
|
|
|
[ [[ "cos" 1 ]] cos ]
|
|
|
|
[ [[ "tan" 1 ]] tan ]
|
|
|
|
[ [[ "max" 2 ]] max ]
|
|
|
|
[ [[ "min" 2 ]] min ]
|
|
|
|
[ [[ "," 2 ]] append ]
|
|
|
|
[ [[ "," 1 ]] concat ]
|
|
|
|
[ [[ "sn" 3 ]] -rot set-nth ]
|
|
|
|
[ [[ "prod" 1 ]] product ]
|
|
|
|
[ [[ "vec" 1 ]] >vector ]
|
2005-10-29 23:25:38 -04:00
|
|
|
} ;
|
2005-08-23 14:43:12 -04:00
|
|
|
|
|
|
|
: drc ( list -- list )
|
|
|
|
#! all of list except last element (backwards cdr)
|
|
|
|
dup cdr [
|
|
|
|
uncons drc cons
|
|
|
|
] [
|
|
|
|
drop f
|
2006-01-24 21:52:17 -05:00
|
|
|
] if ;
|
2005-08-23 14:43:12 -04:00
|
|
|
|
|
|
|
: map-with-left ( seq object quot -- seq )
|
|
|
|
[ swapd call ] cons swapd map-with ; inline
|
|
|
|
|
|
|
|
: high-functions
|
|
|
|
#! Higher-order functions
|
|
|
|
#! Gives quotation applicable to quotation and rest of stack
|
2005-10-29 23:25:38 -04:00
|
|
|
H{
|
2005-08-25 18:02:30 -04:00
|
|
|
[ [[ "!" 2 ]] 2map ]
|
|
|
|
[ [[ "!" 1 ]] map ]
|
|
|
|
[ [[ ">" 2 ]] map-with ]
|
|
|
|
[ [[ "<" 2 ]] map-with-left ]
|
|
|
|
[ [[ "^" 1 ]] all? ]
|
|
|
|
[ [[ "~" 1 ]] call not ]
|
|
|
|
[ [[ "~" 2 ]] call not ]
|
|
|
|
[ [[ "/" 2 ]] swapd reduce ]
|
|
|
|
[ [[ "\\" 2 ]] swapd accumulate ]
|
2005-10-29 23:25:38 -04:00
|
|
|
} ;
|
2005-08-23 14:43:12 -04:00
|
|
|
|
|
|
|
: get-hash ( key table -- value )
|
|
|
|
#! like hash but throws exception if f
|
|
|
|
dupd hash [ nip ] [
|
|
|
|
[ "Key not found " write . ] string-out throw
|
2006-01-24 21:52:17 -05:00
|
|
|
] if* ;
|
2005-08-23 14:43:12 -04:00
|
|
|
|
|
|
|
: >apply< ( apply -- func args )
|
|
|
|
dup apply-func swap apply-args ;
|
|
|
|
|
|
|
|
: make-apply ( arity apply/string -- quot )
|
|
|
|
dup string? [
|
|
|
|
swons functions get-hash
|
|
|
|
] [
|
|
|
|
>apply< car >r over r> make-apply
|
|
|
|
-rot swons high-functions get-hash cons
|
2006-01-24 21:52:17 -05:00
|
|
|
] if ;
|
2005-08-23 14:43:12 -04:00
|
|
|
|
|
|
|
: get-function ( apply -- quot )
|
|
|
|
>apply< length swap make-apply ;
|
|
|
|
|
|
|
|
M: apply compile-ast ! function application
|
2005-08-25 18:02:30 -04:00
|
|
|
[ apply-args [ swap ] accumulator [ drop ] append ] keep
|
2005-08-23 14:43:12 -04:00
|
|
|
get-function append ;
|
|
|
|
|
|
|
|
: push-list ( list item -- list )
|
|
|
|
unit append ;
|
|
|
|
|
|
|
|
: parse-comp ( args string -- quot )
|
|
|
|
#! Compile a string into a quotation w/o prologue
|
|
|
|
parse-full compile-ast ;
|
|
|
|
|
|
|
|
: prologue ( args -- quot )
|
|
|
|
#! Build the prolog for a function
|
|
|
|
[
|
|
|
|
length dup , \ <array> ,
|
|
|
|
[ 1 - ] keep [
|
|
|
|
2dup - [ swap set-array-nth ] cons , \ keep ,
|
|
|
|
] repeat drop
|
2005-09-01 16:07:22 -04:00
|
|
|
] [ ] make ;
|
2005-08-23 14:43:12 -04:00
|
|
|
|
|
|
|
: ast>quot ( args ast -- quot )
|
|
|
|
over prologue -rot compile-ast append ;
|
|
|
|
|
2005-09-01 16:07:22 -04:00
|
|
|
: define-math ( seq -- )
|
|
|
|
" " join
|
2005-08-25 18:02:30 -04:00
|
|
|
dup parse-full apply-args uncons car swap
|
2005-08-23 14:43:12 -04:00
|
|
|
>apply< >r create-in r>
|
|
|
|
[ "math-args" set-word-prop ] 2keep
|
|
|
|
>r tuck >r >r swap "code" set-word-prop r> r> r>
|
|
|
|
rot ast>quot define-compound ;
|
|
|
|
|
|
|
|
: MATH:
|
|
|
|
#! MATH: sq[x]=x*x ;
|
|
|
|
"in-definition" on
|
|
|
|
string-mode on
|
|
|
|
[
|
2005-09-01 16:07:22 -04:00
|
|
|
string-mode off define-math
|
2005-08-23 14:43:12 -04:00
|
|
|
] f ; parsing
|
|
|
|
|
|
|
|
: TEST-MATH:
|
|
|
|
#! Executes and prints the result of a math
|
|
|
|
#! expression at parsetime
|
|
|
|
string-mode on [
|
2005-08-25 18:02:30 -04:00
|
|
|
" " join string-mode off parse-full
|
2005-08-23 14:43:12 -04:00
|
|
|
f swap ast>quot call .
|
|
|
|
] f ; parsing
|
|
|
|
|
|
|
|
! PREDICATE: compound infix-word "code" word-prop ;
|
|
|
|
! M: infix-word definer
|
|
|
|
! drop POSTPONE: MATH: ;
|
|
|
|
! M: infix-word class.
|
|
|
|
! "code" word-prop write " ;" print ;
|
|
|
|
!
|
|
|
|
! Redefine compound to not include infix words so see works
|
|
|
|
! IN: words
|
|
|
|
! USING: kernel words parse-k ;
|
|
|
|
!
|
|
|
|
! PREDICATE: word compound
|
|
|
|
! dup word-primitive 1 = swap infix-word? not and ;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
MATH: quadratic[a;b;c] =
|
|
|
|
plusmin[(-b)/2*a;(sqrt(b^2)-4*a*c)/2*a] ;
|