#+HTML_HEAD:
#+TITLE: 小蟬之核 / core of cicada-nymph
#+AUTHOR: 謝宇恆 / XIE Yuheng
* todo
*** >< code generation for interfaces of data-structure
*** >< the size of file
*** >< better structure for IO functions
* only one error-code->string is not enough
*** >< write-with-color
* for better report
*** type check
*** >< view the core as a special module
* re-import core every time
*** optimize with type info
*** fast tangle
*** debug-REPL
*** 漢語 alias
*** language-level support for creating and managing processes
* module-meta
*** core-test
#+begin_src cicada-nymph :tangle core-test.cn
::::::::
author: XIE Yuheng
do: "* (core-test) finished" .s .l
========
#+end_src
* writers
*** note name of writers
* the use of "." as prefix
is inherited from Forth
* table
| . | pretty_write_integer | assembly |
| .i | write_integer | core |
| .s | write_string | assembly |
| .l | linefeed | core |
| .b | write-byte | |
*** .l .i .b
#+begin_src cicada-nymph :tangle core.cn
: .l
<< -- >>
10 write-byte
end
; define-function
: .i
<< -- >>
write-integer
end
; define-function
: .b
<< byte -- >>
write-byte
end
; define-function
#+end_src
* jojo-compiler-syntax
*** 記 條件轉跳
* one predicate can make two branchs
three predicates can make four branchs
three predicates may only make three branchs
but indeed there must be an invisible branch
*** literal-word:[if|else|then]?
#+begin_src cicada-nymph :tangle core.cn
: literal-word:if?
<< word[address, length] -- bool >>
"if" string:equal?
end
; define-function
: literal-word:else?
<< word[address, length] -- bool >>
"else" string:equal?
end
; define-function
: literal-word:then?
<< word[address, length] -- bool >>
"then" string:equal?
end
; define-function
#+end_src
*** jojo-compiler-syntax:if
#+begin_src cicada-nymph :tangle core.cn
: jojo-compiler-syntax:if
<< jo, string[address, length], literal-word:if --
address, jo, string[address, length] >>
drop2
jo instruction,false?branch
jojo-area,stay
*jojo-area,current-free-address* xxx|swap|x
0 jojo-area,stay
end
; define-function
#+end_src
*** jojo-compiler-syntax:else
#+begin_src cicada-nymph :tangle core.cn
: jojo-compiler-syntax:else
<< address, jo, string[address, length], literal-word:else --
address, jo, string[address, length] >>
drop2
jo instruction,branch
jojo-area,stay
x|swap|xxx
*jojo-area,current-free-address* xxxx|swap|x
0 jojo-area,stay
<< address, string[address, length], address >>
*jojo-area,current-free-address*
over sub *cell-size* div
swap set
end
; define-function
#+end_src
*** jojo-compiler-syntax:then
#+begin_src cicada-nymph :tangle core.cn
: jojo-compiler-syntax:then
<< address, jo, string[address, length], literal-word:then --
jo, string[address, length] >>
drop2
x|swap|xxx
*jojo-area,current-free-address*
over sub *cell-size* div
swap set
end
; define-function
#+end_src
*** test if & else & then
#+begin_src cicada-nymph :tangle core-test.cn
: .12
<< 1 2 -- >>
2 equal? if
"(^-^)" .s
1 equal? if
"\^o^/" .s
else
"_____" .s
then
else
"_____" .s
1 equal? if
"\^o^/" .s
else
"_____" .s
then
then
end
; test-function
: "* (testing) nested if & else & then" .s .l
1 2 .12 .l
6 2 .12 .l
1 6 .12 .l
6 6 .12 .l
; test-do
#+end_src
*** test if & else & then by factorial
#+begin_src cicada-nymph :tangle core-test.cn
: factorial
<< number -- number >>
dup
one? if
end
then
dup sub1 factorial
mul
end
; test-function
: "* (testing) if & else & then by factorial" .s .l
1 factorial 1 equal?
2 factorial 2 equal? and
3 factorial 6 equal? and
4 factorial 24 equal? and
5 factorial 120 equal? and
6 factorial 720 equal? and test
end
; test-do
#+end_src
*** literal-word:loop?
#+begin_src cicada-nymph :tangle core.cn
: literal-word:loop?
<< word[address, length] -- bool >>
"loop" string:equal?
end
; define-function
#+end_src
*** jojo-compiler-syntax:loop
#+begin_src cicada-nymph :tangle core.cn
: jojo-compiler-syntax:loop
<< jo, string[address, length], literal-word:loop --
jo, string[address, length] >>
drop2
jo tail-call
jojo-area,stay
x|over|xx
jojo-area,stay
end
; define-function
#+end_src
*** literal-word:recur?
#+begin_src cicada-nymph :tangle core.cn
: literal-word:recur?
<< word[address, length] -- bool >>
"recur" string:equal?
end
; define-function
#+end_src
*** jojo-compiler-syntax:recur
#+begin_src cicada-nymph :tangle core.cn
: jojo-compiler-syntax:recur
<< jo, string[address, length], literal-word:recur --
jo, string[address, length] >>
drop2
x|over|xx
jojo-area,stay
end
; define-function
#+end_src
*** test loop & recur by factorial
#+begin_src cicada-nymph :tangle core-test.cn
: recur-factorial
<< number -- number >>
dup
one? if
end
then
dup sub1 recur mul
end
; test-function
: "* (testing) recur by factorial" .s .l
1 recur-factorial 1 equal?
2 recur-factorial 2 equal? and
3 recur-factorial 6 equal? and
4 recur-factorial 24 equal? and
5 recur-factorial 120 equal? and
6 recur-factorial 720 equal? and test
end
; test-do
: loop-factorial,loop
<< counter, product -- product >>
over one? if
swap drop
end
then
over mul
swap sub1 swap
loop
; define-function
: loop-factorial
<< number -- number >>
1 loop-factorial,loop
end
; define-function
: "* (testing) loop by factorial" .s .l
1 loop-factorial 1 equal?
2 loop-factorial 2 equal? and
3 loop-factorial 6 equal? and
4 loop-factorial 24 equal? and
5 loop-factorial 120 equal? and
6 loop-factorial 720 equal? and test
end
; test-do
#+end_src
*** test recur by fibonacci
#+begin_src cicada-nymph
<< 0 1 1 2 3 5 8 13 21 34 55 89 144 233 >>
: fibonacci
<< number -- number >>
dup zero? if
end
then
dup one? if
end
then
dup sub1 recur
swap sub1 sub1 recur
add
end
; define-function
: "* test recur by fibonacci" .s .l
0 fibonacci 0 equal?
1 fibonacci 1 equal? and
2 fibonacci 1 equal? and
3 fibonacci 2 equal? and
4 fibonacci 3 equal? and
5 fibonacci 5 equal? and
6 fibonacci 8 equal? and
7 fibonacci 13 equal? and
8 fibonacci 21 equal? and
9 fibonacci 34 equal? and
10 fibonacci 55 equal? and
11 fibonacci 89 equal? and
12 fibonacci 144 equal? and
13 fibonacci 233 equal? and
14 fibonacci 377 equal? and
15 fibonacci 610 equal? and
16 fibonacci 987 equal? and
17 fibonacci 1597 equal? and
18 fibonacci 2584 equal? and
19 fibonacci 4181 equal? and
20 fibonacci 6765 equal? and test
end
; test-do
#+end_src
*** more,syntax-rule-set:jojo-compiler
#+begin_src cicada-nymph :tangle core.cn
: more,syntax-rule-set:jojo-compiler
<< -- >>
jojo-compiler:*syntax-rule-set*
dup jo literal-word:if? jo jojo-compiler-syntax:if syntax-rule:add
dup jo literal-word:else? jo jojo-compiler-syntax:else syntax-rule:add
dup jo literal-word:then? jo jojo-compiler-syntax:then syntax-rule:add
dup jo literal-word:loop? jo jojo-compiler-syntax:loop syntax-rule:add
jo literal-word:recur? jo jojo-compiler-syntax:recur syntax-rule:add
end
; define-function
more,syntax-rule-set:jojo-compiler
#+end_src
* name & name-hash-table
*** note
* the name-hash-table
is used both in cicada-nymph and cicada-language
*** allocate
***** note
* an interface of *un-initialized-memory*
***** allocate-memory
#+begin_src cicada-nymph :tangle core.cn
: allocate-memory
<< size -- address >>
dup *un-initialized-memory,current-free-address* clear-memory
*un-initialized-memory,current-free-address* swap << address as return value >>
address *un-initialized-memory,current-free-address* add-set
end
; define-function
#+end_src
*** *name-hash-table*
* the following are some prime number
ready to be used
* 1000003 about 976 k
* 1000033
* 1000333
* 100003 about 97 k
* 100333
* 997
* 499
#+begin_src cicada-nymph :tangle core.cn
100333
<< drop 13 >>
: *name-hash-table,size*
; define-variable,with-tos
*cell-size* 5 mul
: *name-hash-table,unit*
; define-variable,with-tos
*name-hash-table,size*
*name-hash-table,unit* mul allocate-memory
: *name-hash-table*
; define-variable,with-tos
0
: *name-hash-table,counter*
; define-variable,with-tos
#+end_src
*** *name-hash-table,string-area*
#+begin_src cicada-nymph :tangle core.cn
*name-hash-table,size* 32 mul
: *name-hash-table,string-area,size*
; define-variable,with-tos
*name-hash-table,string-area,size*
allocate-memory
: *name-hash-table,string-area*
; define-variable,with-tos
*name-hash-table,string-area*
: *name-hash-table,string-area,current-free-address*
; define-variable,with-tos
#+end_src
*** name-hash-table,string-area,stay
#+begin_src cicada-nymph :tangle core.cn
: name-hash-table,string-area,stay
<< string[address, length] -- >>
tuck
*name-hash-table,string-area,current-free-address*
string->buffer!
address *name-hash-table,string-area,current-free-address*
add-set
end
; define-function
#+end_src
*** make-string,for-name
#+begin_src cicada-nymph :tangle core.cn
: make-string,for-name
<< string[address, length] -- string-copy[address, length] >>
*name-hash-table,string-area,current-free-address*
xx|swap|x
tuck
name-hash-table,string-area,stay
end
; define-function
#+end_src
*** name
***** note
* a name is an index into name-hash-table
* an entry can be viewed
1. as a point
2. as an orbit
* in a name entry we have the following fields
|------+---------------------|
| name | name-string-address |
| | name-string-length |
|------+---------------------|
| | orbit-length |
| | orbiton |
| | jo |
|------+---------------------|
1. name-string-address
0 denotes name not used
2. orbit-length
as an orbit
its length gets updated
3. as a point
it is on an orbit
4. jo
0 denotes name not used as jo
***** name->address
#+begin_src cicada-nymph :tangle core.cn
: name->address
<< name -- address >>
*name-hash-table,unit* mul
*name-hash-table* add
end
; define-function
#+end_src
***** name,used?
#+begin_src cicada-nymph :tangle core.cn
: name,used?
<< name -- bool >>
name->address
get zero? false?
end
; define-function
#+end_src
***** name,used-as-jo?
#+begin_src cicada-nymph :tangle core.cn
: name,used-as-jo?
<< name -- bool >>
name->address
*cell-size* 4 mul add
get zero? not
end
; define-function
#+end_src
***** name->string
#+begin_src cicada-nymph :tangle core.cn
: name->string
<< name -- string[address, length] >>
name->address
2 n-get
end
; define-function
#+end_src
***** name,get-orbit-length
#+begin_src cicada-nymph :tangle core.cn
: name,get-orbit-length
<< name -- orbit-length >>
name->address
*cell-size* 2 mul add
get
end
; define-function
#+end_src
***** name,get-orbiton
#+begin_src cicada-nymph :tangle core.cn
: name,get-orbiton
<< name -- orbiton >>
name->address
*cell-size* 3 mul add
get
end
; define-function
#+end_src
***** name,get-jo
#+begin_src cicada-nymph :tangle core.cn
: name,get-jo
<< name -- jo >>
name->address
*cell-size* 4 mul add
get
end
; define-function
#+end_src
***** name,set-string
#+begin_src cicada-nymph :tangle core.cn
: name,set-string
<< string[address, length], name -- >>
>:name
make-string,for-name
:name name->address
2 n-set
end
; define-function
#+end_src
***** name,set-orbit-length
#+begin_src cicada-nymph :tangle core.cn
: name,set-orbit-length
<< orbit-length, name -- >>
name->address
*cell-size* 2 mul add
set
end
; define-function
#+end_src
***** name,set-orbiton
#+begin_src cicada-nymph :tangle core.cn
: name,set-orbiton
<< orbiton, name -- >>
name->address
*cell-size* 3 mul add
set
end
; define-function
#+end_src
***** name,set-jo
#+begin_src cicada-nymph :tangle core.cn
: name,set-jo
<< jo, name -- >>
name->address
*cell-size* 4 mul add
set
end
; define-function
#+end_src
***** name,no-collision?
#+begin_src cicada-nymph :tangle core.cn
: name,no-collision?
<< name -- bool >>
dup name,get-orbiton
equal?
end
; define-function
#+end_src
*** name-hash-table
***** note interface
* open addressing
for we do not need to delete
* math
* hash
* memory
* insert
* search
* function
* string->name
* name->string
***** name-hash-table,hash
* prime table size
* linear probing
#+begin_src cicada-nymph :tangle core.cn
: name-hash-table,hash
<< number, counter -- index >>
add *name-hash-table,size* mod
end
; define-function
#+end_src
***** string->finite-carry-sum
#+begin_src cicada-nymph :tangle core.cn
16
: *max-carry-position*
; define-variable,with-tos
: string->finite-carry-sum,loop
<< carry-sum, string[address, length], counter -- carry-sum >>
over zero? if
drop drop2
end
then
dup *max-carry-position* greater-than? if
drop 0 << re-start from 0 >>
then
xx|over|x
string:byte over
2 swap power
mul
x|swap|xxxx add xxx|swap|x
add1 xx|swap|x
string:byte-tail x|swap|xx
loop
; define-function
: string->finite-carry-sum
<< string[address, length] -- carry-sum >>
0 xx|swap|x << carry-sum >>
0 << counter >>
string->finite-carry-sum,loop
end
; define-function
#+end_src
***** name-hash-table,search
#+begin_src cicada-nymph :tangle core.cn
: name-hash-table,search,loop
<< string[address, length], number, counter
-- name, true
-- name, false >>
>:counter >:number >::string
:number :counter name-hash-table,hash
>:name
:number 0 name-hash-table,hash
>:orbit
:name name,used? false? if
:name false
end
then
:name name->string
::string string:equal? if
:name true
end
then
:name name,get-orbit-length
:counter equal? if
:name false
end
then
::string
:number :counter add1
loop
; define-function
: name-hash-table,search
<< string[address, length]
-- name, true
-- name, false >>
dup2 string->finite-carry-sum
0 name-hash-table,search,loop
end
; define-function
#+end_src
***** name-hash-table,insert
* I found that (insert) can not re-use (search)
#+begin_src cicada-nymph :tangle core.cn
: name-hash-table,insert,loop
<< string[address, length], number, counter
-- name, true
-- name, false >>
>:counter >:number >::string
:number :counter name-hash-table,hash
>:name
:number 0 name-hash-table,hash
>:orbit
:name name,used? false? if
::string :name
name,set-string
:orbit :name
name,set-orbiton
:counter :orbit
name,set-orbit-length
1 address *name-hash-table,counter* add-set
:name true
end
then
:name name->string
::string string:equal? if
:name true
end
then
:counter *name-hash-table,size* equal? if
:name false
end
then
::string
:number
:counter add1
loop
; define-function
: name-hash-table,insert
<< string[address, length]
-- name, true
-- name, false >>
dup2 string->finite-carry-sum
0 name-hash-table,insert,loop
end
; define-function
#+end_src
***** string->name
* error handling here
#+begin_src cicada-nymph :tangle core.cn
: string->name
<< string[address, length] -- name >>
name-hash-table,insert
false? if
"* (string->name) *name-hash-table* is full!" .s .l
end
then
end
; define-function
#+end_src
***** note about report
* report point orbit by orbit
in the following format
* {index} string # orbit-lenght
* {index} string
* {index} string
* {index} string
***** name-hash-table,report
#+begin_src cicada-nymph :tangle core.cn
: name-hash-table,report,orbit
<< name, counter -- >>
over name,get-orbit-length
over less-than? if
drop2
end
then
over name->string string->finite-carry-sum
over name-hash-table,hash
dup name,get-orbiton
<< name, counter, new-name, orbiton >>
x|over|xxx name->string string->finite-carry-sum
0 name-hash-table,hash
equal? if
" {" .s
dup write-number
"} " .s
name->string .s
.l
else
drop
then
add1
loop
; define-function
: name-hash-table,report,loop
<< name -- >>
dup *name-hash-table,size* equal? if
drop
end
then
dup name,used? if
dup name,no-collision? if
<< * {index} string # orbit-lenght >>
"* {" .s
dup write-number
"} " .s
dup name->string .s
" # " .s
dup name,get-orbit-length
write-number
.l
dup 1 name-hash-table,report,orbit
then
then
add1
loop
; define-function
: name-hash-table,report
<< -- >>
0 name-hash-table,report,loop
"* totally : " .s
*name-hash-table,counter* write-number
.l
end
; define-function
#+end_src
***** test string->name & name->string
* set *name-hash-table,size* to a small number [for example 13]
then use the following function
and (name-hash-table,report) to do test
#+begin_src cicada-nymph :tangle core-test.cn
: "* (testing) string->name & name->string" .s .l
"a-000" dup2 string->name name->string string:equal?
"a-111" dup2 string->name name->string string:equal? and
"a-222" dup2 string->name name->string string:equal? and
"a-333" dup2 string->name name->string string:equal? and
"a-444" dup2 string->name name->string string:equal? and
"a-555" dup2 string->name name->string string:equal? and
"a-666" dup2 string->name name->string string:equal? and
"a-777" dup2 string->name name->string string:equal? and
"a-888" dup2 string->name name->string string:equal? and
"a-999" dup2 string->name name->string string:equal? and
"b-000" dup2 string->name name->string string:equal? and
"b-111" dup2 string->name name->string string:equal? and
"b-222" dup2 string->name name->string string:equal? and
"b-333" dup2 string->name name->string string:equal? and
"b-444" dup2 string->name name->string string:equal? and
"b-555" dup2 string->name name->string string:equal? and
"b-666" dup2 string->name name->string string:equal? and
"b-777" dup2 string->name name->string string:equal? and
"b-888" dup2 string->name name->string string:equal? and
"b-999" dup2 string->name name->string string:equal? and test
end
; test-do
<<
name-hash-table,report
>>
#+end_src
***** name-hash-table,find-jo
#+begin_src cicada-nymph :tangle core.cn
: name-hash-table,find-jo
<< word[address, length]
-- jo, true
-- false >>
name-hash-table,search if
else
drop
false
end
then
dup name,used-as-jo? if
name,get-jo
true
end
then
drop
false
end
; define-function
#+end_src
***** test name-hash-table,find-jo
#+begin_src cicada-nymph
: "* (testing) name-hash-table,find-jo" .s .l
"add" name-hash-table,find-jo if
name->string "add" string:equal? test
else
false test
then
; test-do
#+end_src
* global-naming-stack & name-record
*** note global-naming-stack
* (define-*) push
(undo) pop
*** note name-record
* *global-naming-stack* contain name-record
* structure
| name-record | old-jo |
| | name |
| | new-jo |
*** *global-naming-stack*
#+begin_src cicada-nymph :tangle core.cn
100 1024 mul
: global-naming-stack:*size*
; define-variable,with-tos
3 *cell-size* mul
: global-naming-stack:*unit*
; define-variable,with-tos
global-naming-stack:*size*
global-naming-stack:*unit* mul allocate-memory
: *global-naming-stack*
; define-variable,with-tos
*global-naming-stack*
: global-naming-stack:*pointer*
; define-variable,with-tos
#+end_src
*** name-record:[get|set]-old-jo
#+begin_src cicada-nymph :tangle core.cn
: name-record:get-old-jo
<< name-record -- old-jo >>
get
end
; define-function
: name-record:set-old-jo
<< old-jo, name-record -- >>
set
end
; define-function
#+end_src
*** name-record:[get|set]-name
#+begin_src cicada-nymph :tangle core.cn
: name-record:get-name
<< name-record -- name >>
*cell-size* add get
end
; define-function
: name-record:set-name
<< name, name-record -- >>
*cell-size* add set
end
; define-function
#+end_src
*** name-record:[get|set]-new-jo
#+begin_src cicada-nymph :tangle core.cn
: name-record:get-new-jo
<< name-record -- new-jo >>
*cell-size* 2 mul add get
end
; define-function
: name-record:set-new-jo
<< new-jo, name-record -- >>
*cell-size* 2 mul add set
end
; define-function
#+end_src
*** global-naming-stack:record-jo
#+begin_src cicada-nymph :tangle core.cn
: global-naming-stack:record-jo
<< jo, name -- >>
dup name,get-jo
global-naming-stack:*pointer* name-record:set-old-jo
dup2 name,set-jo
global-naming-stack:*pointer* name-record:set-name
global-naming-stack:*pointer* name-record:set-new-jo
global-naming-stack:*unit* address global-naming-stack:*pointer* add-set
end
; define-function
#+end_src
*** global-naming-stack:delete-last-record
#+begin_src cicada-nymph :tangle core.cn
: global-naming-stack:delete-last-record
<< -- >>
global-naming-stack:*unit*
address global-naming-stack:*pointer*
sub-set
global-naming-stack:*pointer* name-record:get-old-jo
global-naming-stack:*pointer* name-record:get-name
name,set-jo
end
; define-function
#+end_src
*** jo,find-name
#+begin_src cicada-nymph :tangle core.cn
: jo,find-name,loop
<< jo, current-record
-- name, true
-- false >>
dup *global-naming-stack* equal? if
drop2
false
end
then
global-naming-stack:*unit* sub
dup >:name-record
over
:name-record name-record:get-new-jo equal? if
drop2
:name-record name-record:get-name
true
end
then
loop
; define-function
: jo,find-name
<< jo
-- name, true
-- false >>
global-naming-stack:*pointer*
jo,find-name,loop
end
; define-function
#+end_src
*** name-hash-table,record-jo,by-link
#+begin_src cicada-nymph :tangle core.cn
: name-hash-table,record-jo,by-link
<< link -- >>
>:link
:link link->jo
:link link->name-string string->name
global-naming-stack:record-jo
end
; define-function
#+end_src
* jojo-compiler-syntax:quote
*** quote-word?
#+begin_src cicada-nymph :tangle core.cn
: quote-word?
<< word[address, length] -- bool >>
dup 1 less-or-equal? if
drop2
false
end
then
string:byte "'" string:byte equal?
end
; define-function
#+end_src
*** jojo-compiler-syntax:quote
#+begin_src cicada-nymph :tangle core.cn
: jojo-compiler-syntax:quote
<< string[address, length], word[address, length] --
string[address, length] >>
jo instruction,literal
jojo-area,stay
string:byte-tail string->name
jojo-area,stay
end
; define-function
#+end_src
*** more,syntax-rule-set:jojo-compiler
#+begin_src cicada-nymph :tangle core.cn
: more,syntax-rule-set:jojo-compiler
<< -- >>
jojo-compiler:*syntax-rule-set*
jo quote-word? jo jojo-compiler-syntax:quote syntax-rule:add
end
; define-function
more,syntax-rule-set:jojo-compiler
#+end_src
*** test jojo-compiler-syntax:quote
#+begin_src cicada-nymph :tangle core-test.cn
: "* (testing) jojo-compiler-syntax:quote" .s .l
'testing--jojo-compiler-syntax:quote name->string
"testing--jojo-compiler-syntax:quote" string:equal? test
; test-do
#+end_src
* scope-stack & offset-record
*** *scope-stack*
#+begin_src cicada-nymph :tangle core.cn
10 1024 mul
: scope-stack:*size*
; define-variable,with-tos
2 *cell-size* mul
: scope-stack:*unit*
; define-variable,with-tos
scope-stack:*size*
scope-stack:*unit* mul allocate-memory
: *scope-stack*
; define-variable,with-tos
*scope-stack*
: scope-stack:*pointer*
; define-variable,with-tos
#+end_src
*** note offset-record
* structure
| offset-record | name |
| | offset |
specially
| scope-delimiter | 0 |
| | 0 |
*** offset-record,[get|set]-name
#+begin_src cicada-nymph :tangle core.cn
: offset-record,get-name
<< offset-record -- name >>
get
end
; define-function
: offset-record,set-name
<< name, offset-record -- >>
set
end
; define-function
#+end_src
*** offset-record,[get|set]-offset
#+begin_src cicada-nymph :tangle core.cn
: offset-record,get-offset
<< offset-record -- offset >>
*cell-size* add get
end
; define-function
: offset-record,set-offset
<< offset, offset-record -- >>
*cell-size* add set
end
; define-function
#+end_src
*** offset-record,scope-delimiter?
#+begin_src cicada-nymph :tangle core.cn
: offset-record,scope-delimiter?
<< offset-record -- bool >>
offset-record,get-name zero?
end
; define-function
#+end_src
*** scope-stack:find
* from the pointer to the base
#+begin_src cicada-nymph :tangle core.cn
: scope-stack:find,loop
<< name, cursor
-- offset-record, true
-- false >>
dup *scope-stack* equal? if
drop2
false
end
then
scope-stack:*unit* sub >:cursor
>:name
:cursor offset-record,get-name
:name equal? if
:cursor
true
end
then
:name
:cursor
loop
; define-function
: scope-stack:find
<< name
-- offset-record, true
-- false >>
scope-stack:*pointer*
scope-stack:find,loop
end
; define-function
#+end_src
*** scope-stack:get-current-offset
#+begin_src cicada-nymph :tangle core.cn
: scope-stack:get-current-offset
<< -- offset >>
*scope-stack* scope-stack:*pointer* equal? if
"* (scope-stack:get-current-offset) fail" .s .l
" for the scope-stack is empty" .s .l
end
then
scope-stack:*pointer*
scope-stack:*unit* sub
dup offset-record,scope-delimiter? if
drop
0
end
then
dup
offset-record,get-name
name->string count-front-colon *cell-size* mul
swap
offset-record,get-offset
add
end
; define-function
#+end_src
* await & awake
*** note notation
* table
| 期待 [非局部退出點] | await [make non-local-exit-piont] |
| 動意 [非局部退出信號] | awake [non-local-exit-signal] |
*** *awaiting-stack*
#+begin_src cicada-nymph :tangle core.cn
10 1024 mul
: awaiting-stack:*size*
; define-variable,with-tos
4 *cell-size* mul
: awaiting-stack:*unit*
; define-variable,with-tos
awaiting-stack:*size*
awaiting-stack:*unit* mul allocate-memory
: *awaiting-stack*
; define-variable,with-tos
*awaiting-stack*
: awaiting-stack:*pointer*
; define-variable,with-tos
#+end_src
*** note action
* structure
| action | function |
| | argument-stack |
| | return-stack |
| | name |
*** action,[get|set]-function
#+begin_src cicada-nymph :tangle core.cn
: action,get-function
<< action -- function >>
get
end
; define-function
: action,set-function
<< function, action -- >>
set
end
; define-function
#+end_src
*** action,[get|set]-argument-stack-pointer
#+begin_src cicada-nymph :tangle core.cn
: action,get-argument-stack-pointer
<< action -- argument-stack-pointer >>
*cell-size* add get
end
; define-function
: action,set-argument-stack-pointer
<< argument-stack-pointer, action -- >>
*cell-size* add set
end
; define-function
#+end_src
*** action,[get|set]-return-stack-pointer
#+begin_src cicada-nymph :tangle core.cn
: action,get-return-stack-pointer
<< action -- return-stack-pointer >>
*cell-size* 2 mul add get
end
; define-function
: action,set-return-stack-pointer
<< return-stack-pointer, action -- >>
*cell-size* 2 mul add set
end
; define-function
#+end_src
*** action,[get|set]-name
#+begin_src cicada-nymph :tangle core.cn
: action,get-name
<< action -- name >>
*cell-size* 3 mul add get
end
; define-function
: action,set-name
<< name, action -- >>
*cell-size* 3 mul add set
end
; define-function
#+end_src
*** drop-awaiting-stack
#+begin_src cicada-nymph :tangle core.cn
: drop-awaiting-stack
<< -- >>
awaiting-stack:*unit* address awaiting-stack:*pointer* sub-set
end
; define-function
#+end_src
*** awaiting-stack:find
* from the pointer to the base
#+begin_src cicada-nymph :tangle core.cn
: awaiting-stack:find,loop
<< name, cursor
-- action, true
-- false >>
dup *awaiting-stack* equal? if
drop2
false
end
then
awaiting-stack:*unit* sub >:cursor
>:name
:cursor action,get-name
:name equal? if
:cursor
true
end
then
:name
:cursor
loop
; define-function
: awaiting-stack:find
<< name
-- action, true
-- false >>
awaiting-stack:*pointer*
awaiting-stack:find,loop
end
; define-function
#+end_src
*** await
#+begin_src cicada-nymph :tangle core.cn
: await
<< function, name -- >>
>:name
>:function
snapshot-the-stack-pointer
*the-stack-pointer-snapshot* >:argument-stack-pointer
get-return-stack-pointer
return-stack:*unit* 2 mul sub >:return-stack-pointer
awaiting-stack:*pointer* >:action
awaiting-stack:*unit* address awaiting-stack:*pointer* add-set
:function
:action
action,set-function
:argument-stack-pointer
:action
action,set-argument-stack-pointer
:return-stack-pointer
:action
action,set-return-stack-pointer
:name
:action
action,set-name
jo drop-awaiting-stack
:return-stack-pointer
return-stack:insert-jo
end
; define-function
#+end_src
*** action,apply
#+begin_src cicada-nymph :tangle core.cn
: action,apply
<< action -- >>
>:action
:action address awaiting-stack:*pointer* set
:action action,get-return-stack-pointer
:action action,get-function
apply-with-return-point
; define-function
#+end_src
*** action,reset-the-stack
#+begin_src cicada-nymph :tangle core.cn
: action,reset-the-stack
<< -- >>
awaiting-stack:*pointer* action,get-argument-stack-pointer
set-argument-stack-pointer
end
; define-function
#+end_src
*** awake
#+begin_src cicada-nymph :tangle core.cn
: awake
<< name -- >>
>:name
:name awaiting-stack:find if
action,apply
end
then
"* (awake) can not find action in awaiting-stack by : " .s :name name->string .s .l
end
; define-function
#+end_src
*** test await & awake
#+begin_src cicada-nymph :tangle core-test.cn
: testing-awake
<< -- >>
'signal awake
end
; test-function
: testing-await
<< -- >>
"after reset-the-stack"
[ "before reset-the-stack" string:equal? test
action,reset-the-stack
"after reset-the-stack" string:equal? test
end ]
'signal await
"something in the stack"
"before reset-the-stack"
testing-awake
end
; test-function
: "* (testing) await & awake" .s .l
testing-await
; test-do
#+end_src
* basic-REPL
*** syntax-rule-set:*word-interpreter*
#+begin_src cicada-nymph :tangle core.cn
1024 *cell-size* mul
: *syntax-rule-set:word-interpreter,size*
; define-variable,with-tos
<< for cursor >>
*cell-size* allocate-memory drop
*syntax-rule-set:word-interpreter,size*
allocate-memory
: syntax-rule-set:*word-interpreter*
; define-variable,with-tos
syntax-rule-set:*word-interpreter*
syntax-rule-set:*word-interpreter* *cell-size* sub
set
#+end_src
*** word-interpreter
#+begin_src cicada-nymph :tangle core.cn
: word-interpreter
<< word[address, length] -- unknown >>
dup2 find-syntax if
apply
end
then
dup2
name-hash-table,find-jo if
<< function & primitive-function & variable >>
xx|swap|x drop2
apply
end
then
"* (word-interpreter) meets undefined word : " .s
.s .l
end
; define-function
#+end_src
*** word-interpreter-syntax:bye
#+begin_src cicada-nymph :tangle core.cn
: word-interpreter-syntax:bye
<< literal-word:bye -- >>
drop2
'bye,basic-REPL awake
; define-function
#+end_src
*** bye,basic-REPL
#+begin_src cicada-nymph :tangle core.cn
: bye,basic-REPL
<< -- >>
action,reset-the-stack
drop-syntax-stack
end
; define-function
#+end_src
*** basic-REPL :redefine:
#+begin_src cicada-nymph :tangle core.cn
: basic-REPL,loop
<< unknown -- unknown >>
read-word
word-interpreter
loop
; define-function
: basic-REPL
<< unknown -- unknown >>
jo bye,basic-REPL
'bye,basic-REPL await
syntax-rule-set:*word-interpreter* push-syntax-stack
basic-REPL,loop
end
; define-function
#+end_src
*** number with base
***** 記 原理
* 現在 的 number 就只是 "integer" 而已
更多的數的類型將在 cicada 中實現
* 在 "integer" 這個函數中 我將只支持 對四種進位制的 字符串的 閱讀
* 十進制
10#1231
10#-1231
1231
-1231
* 二進制
2#101001
2#-101001
2#-1011_1001
"-" 和 "_" 的同時存在有點難讀
此時可以用 2#1011_1001 negate
也就是說雖然允許用 "-" 來表示負數
但是不鼓勵這樣做
之所以允許這樣做
是因爲在打印負數的時候需要這種表示方式
不能把 "-123" 打印成 "123 negate"
* 八進制
8#712537
8#-712537
* 十六進制
16#f123acb3
16#-F123ACB3
大寫小寫字母都可以
* one can use "_" to separate the number
to make it more readable
for example
2#1111_0101_0001
* actually, the base can be any 10 based number
even greater then 36
but when the base is greater then 36
not all integer can be represented under this base
for we only have 36 bytes
***** remove-byte!
#+begin_src cicada-nymph :tangle core.cn
: remove-byte!,loop
<< cursor, length, byte -- cursor >>
>:byte
>:length
>:cursor
:length zero? if
:cursor
end
then
:cursor get-byte :byte equal? if
:cursor add1 :length sub1
:cursor
string->buffer!
:cursor
:length sub1
:byte
else
:cursor add1
:length sub1
:byte
then
loop
; define-function
: remove-byte!
<< string[address, length], byte -- string[address, length] >>
x|over|xx >:address
remove-byte!,loop >:cursor
:address
:cursor :address sub
end
; define-function
#+end_src
***** test remove-byte!
#+begin_src cicada-nymph :tangle core-test.cn
: "* (testing) remove-byte!" .s .l
"2#1001_1001"
"_" string:byte remove-byte!
"2#10011001" string:equal?
"___2#1001___1001___"
"_" string:byte remove-byte!
"2#10011001" string:equal? and test
; test-do
#+end_src
***** latin-byte?
#+begin_src cicada-nymph :tangle core.cn
: latin-byte?
<< byte -- bool >>
dup "A" string:byte less-than? if
drop false
end
then
dup "Z" string:byte less-or-equal? if
drop true
end
then
dup "a" string:byte less-than? if
drop false
end
then
dup "z" string:byte less-or-equal? if
drop true
end
then
drop false
end
; define-function
#+end_src
***** latin-byte->number
#+begin_src cicada-nymph :tangle core.cn
: latin-byte->number
<< latin-byte -- number >>
dup "A" string:byte less-than? if
"* (latin-byte->number) the argument must be a latin-byte" .s .l
" but the following byte is less-than 'A' : " .s
.i .l
end
then
dup "Z" string:byte less-or-equal? if
"A" string:byte
sub
10 add
end
then
dup "a" string:byte less-than? if
"* (latin-byte->number) the argument must be a latin-byte" .s .l
" but the following byte is less-than 'a' but greater-then 'Z' : " .s
.i .l
end
then
dup "z" string:byte less-or-equal? if
"a" string:byte
sub
10 add
end
then
"* (latin-byte->number) the argument must be a latin-byte" .s .l
" but the following byte is greater-then 'z' : " .s
.i .l
end
; define-function
#+end_src
***** number->latin-byte
#+begin_src cicada-nymph :tangle core.cn
: number->latin-byte
<< number -- latin-byte >>
10 sub
"a" string:byte
add
end
; define-function
#+end_src
***** wild-digit-string?
#+begin_src cicada-nymph :tangle core.cn
: wild-digit-string?
<< string[address, length] -- bool >>
dup zero? if
drop2 true
end
then
over get-byte
dup digit-byte?
swap latin-byte?
or if
string:byte-tail
loop
then
drop2
false
end
; define-function
#+end_src
***** wild-integer-string?
#+begin_src cicada-nymph :tangle core.cn
: wild-integer-string?
<< string[address, length] -- bool >>
dup zero? if
drop2 false
end
then
dup2 string:byte
"-" string:byte
equal? if
string:byte-tail
wild-digit-string?
end
then
wild-digit-string?
end
; define-function
#+end_src
***** test wild-integer-string?
#+begin_src cicada-nymph :tangle core-test.cn
: "* (testing) wild-integer-string?" .s .l
"" wild-integer-string? false?
" " wild-integer-string? false? and
"_asd" wild-integer-string? false? and
" asd" wild-integer-string? false? and
"asd" wild-integer-string? true? and
"123" wild-integer-string? true? and
"123asd" wild-integer-string? true? and test
; test-do
#+end_src
***** base#wild-integer-string?
* a string for the following format
is viewed as a base#digit-string
#[-]
any "_" in the anywhere of the above string
will be ignored
#+begin_src cicada-nymph :tangle core.cn
: base#wild-integer-string?
<< string[address, length] -- bool >>
128 allocate-local-memory
>:string-address
tuck
:string-address
string->buffer!
:string-address swap
"_" string:byte
remove-byte!
>:new-string-length
>:new-string-address
<< dup2 .s .l 0 end >>
:new-string-address
:new-string-length
"#" string:byte
string:find-byte if
else
false
end
then
>:address-of-#
:new-string-address
:address-of-# :new-string-address sub
>::base-string
:address-of-# add1
:address-of-# :new-string-address sub add1
:new-string-length swap sub
>::wild-integer-string
::base-string digit-string?
::base-string string:empty? not
and if
else
false
end
then
::wild-integer-string wild-integer-string?
::wild-integer-string string:empty? not
and if
true
else
false
then
end
; define-function
#+end_src
***** test base#wild-integer-string?
#+begin_src cicada-nymph :tangle core-test.cn
: "* (testing) base#wild-integer-string?" .s .l
"#" base#wild-integer-string? false?
"##" base#wild-integer-string? false? and
"#___#" base#wild-integer-string? false? and
" " base#wild-integer-string? false? and
"______#__1___" base#wild-integer-string? false? and
"___2___#__1___c29bf210019___漢字" base#wild-integer-string? false? and
"1#1" base#wild-integer-string? true? and
"123#1c29bf219g42" base#wild-integer-string? true? and
"___2___#__1___c29bf210019___g42" base#wild-integer-string? true? and test
; test-do
#+end_src
***** base#wild-integer-string->base-string
#+begin_src cicada-nymph :tangle core.cn
: base#wild-integer-string->base-string
<< string[address, length] -- string[address, length] >>
>:length
>:address
:address
:length
"#" string:byte
string:find-byte if
else
"* (base#wild-integer-string->base-string)" .s .l
" the argument must be a base#wild-integer-string" .s .l
" but the following string does not even have a '#' in it :" .s .l
" " .s
:address :length .s .l
<< to balance the argument-stack or not ??? >>
<< :address :length >>
end
then
>:address-of-#
:address
:address-of-# :address sub
end
; define-function
#+end_src
***** base#wild-integer-string->wild-integer-string
#+begin_src cicada-nymph :tangle core.cn
: base#wild-integer-string->wild-integer-string
<< string[address, length] -- string[address, length] >>
>:length
>:address
:address
:length
"#" string:byte
string:find-byte if
else
"* (base#wild-integer-string->wild-integer-string)" .s .l
" the argument must be a base#wild-integer-string" .s .l
" but the following string does not even have a '#' in it :" .s .l
" " .s
:address :length .s .l
<< to balance the argument-stack or not ??? >>
<< :address :length >>
end
then
>:address-of-#
:address-of-# add1
:address-of-# :address sub add1
:length swap sub
end
; define-function
#+end_src
***** test base#wild-integer-string->base-string
#+begin_src cicada-nymph :tangle core-test.cn
: "* (testing) base#wild-integer-string->base-string" .s .l
<< error
"___2___ __1___c29bf210019___漢字" base#wild-integer-string->base-string
>>
"1#1" base#wild-integer-string->base-string
"1" string:equal?
"123#1c29bf219g42" base#wild-integer-string->base-string
"123" string:equal? and
"___2___#__1___c29bf210019___g42" base#wild-integer-string->base-string
"___2___" string:equal? and test
; test-do
: "* (testing) base#wild-integer-string->wild-integer-string" .s .l
<< error
"___2___ __1___c29bf210019___漢字" base#wild-integer-string->wild-integer-string
>>
"1#1" base#wild-integer-string->wild-integer-string
"1" string:equal?
"123#1c29bf219g42" base#wild-integer-string->wild-integer-string
"1c29bf219g42" string:equal? and
"___2___#__1___c29bf210019___g42" base#wild-integer-string->wild-integer-string
"__1___c29bf210019___g42" string:equal? and test
; test-do
#+end_src
***** wild-integer-string->integer,with-base
#+begin_src cicada-nymph :tangle core.cn
: wild-integer-string->integer,with-base,loop
<< string[address, length], base, sum, counter -- integer >>
>:counter
>:sum
>:base
>:length
>:address
:length zero? if
:sum
end
then
:address get-byte >:byte
:byte digit-byte? if
:byte digit-byte->number
then
:byte latin-byte? if
:byte latin-byte->number
then
:base :counter power
mul
:sum add
>:sum
:address add1
:length sub1
:base
:sum
:counter add1
loop
; define-function
: wild-integer-string->integer,with-base
<< string[address, length], base -- integer >>
>:base
dup zero? if
drop2
0
end
then
dup2 string:byte
"-" string:byte
equal? if
string:byte-tail
-1 >:sign
else
1 >:sign
then
>::string
::string string-reverse!
:base
0 0 wild-integer-string->integer,with-base,loop
:sign mul
::string string-reverse!
drop2
end
; define-function
#+end_src
***** base#wild-integer-string->integer
#+begin_src cicada-nymph :tangle core.cn
: base#wild-integer-string->integer
<< string[address, length] -- integer >>
128 allocate-local-memory
>:address
tuck :address string->buffer!
>:length
:address :length
"_" string:byte remove-byte!
>::string
::string
base#wild-integer-string->base-string
>::base-string
::string
base#wild-integer-string->wild-integer-string
>::wild-integer-string
::base-string
digit-string->number
>:base
::wild-integer-string
:base
wild-integer-string->integer,with-base
end
; define-function
#+end_src
***** test base#wild-integer-string->integer
#+begin_src cicada-nymph :tangle core-test.cn
: "* (testing) base#wild-integer-string->integer" .s .l
"0#111" base#wild-integer-string->integer
0 0 power 1 mul
0 1 power 1 mul add
0 2 power 1 mul add
equal?
"1#111" base#wild-integer-string->integer
1 0 power 1 mul
1 1 power 1 mul add
1 2 power 1 mul add
equal?
and
"10#123" base#wild-integer-string->integer
"_1_0__#_1__2_3_" base#wild-integer-string->integer
10 0 power 3 mul
10 1 power 2 mul add
10 2 power 1 mul add
tuck equal?
xx|swap|x equal? and
and
"2#1000" base#wild-integer-string->integer
"2#_1000_" base#wild-integer-string->integer
2 0 power 0 mul
2 1 power 0 mul add
2 2 power 0 mul add
2 3 power 1 mul add
tuck equal?
xx|swap|x equal? and
and
"2#1111_1111" base#wild-integer-string->integer
2 0 power 1 mul
2 1 power 1 mul add
2 2 power 1 mul add
2 3 power 1 mul add
2 4 power 1 mul add
2 5 power 1 mul add
2 6 power 1 mul add
2 7 power 1 mul add
equal?
and
"16#f_f" base#wild-integer-string->integer
16 0 power 15 mul
16 1 power 15 mul add
equal?
and
"100#111" base#wild-integer-string->integer
100 0 power 1 mul
100 1 power 1 mul add
100 2 power 1 mul add
equal?
and
"64#zzz" base#wild-integer-string->integer
64 0 power 35 mul
64 1 power 35 mul add
64 2 power 35 mul add
equal?
and
"36#zzzz" base#wild-integer-string->integer
36 0 power 35 mul
36 1 power 35 mul add
36 2 power 35 mul add
36 3 power 35 mul add
equal?
and test
; test-do
#+end_src
***** note writers
* a general function
and three special ones
* they all writer integer
* I will implemented them by syntax when needed
***** .#
#+begin_src cicada-nymph :tangle core.cn
: .#,loop
<< number, base, cursor -- cursor >>
>:cursor
>:base
>:number
:number zero? if
:cursor
end
then
:number
:base
divmod >:mod >:div
:mod 10 less-than? if
:mod number->digit-byte
else
:mod number->latin-byte
then
:cursor
set-byte
:div
:base
:cursor add1
loop
; define-function
: .#
<< integer, base -- >>
over zero? if
drop .i
end
then
dup 36 greater-than?
over 2 less-than?
or if
"* (.#) the base " .s .i " is not valid to write a number" .s .l
" a base should in between 2 and 36 includingly" .s .l
" the integer to be written is " .s .i .l
end
then
dup .i
"#" .s
over negative? if
swap negate swap
"-" .s
then
128 allocate-local-memory >:buffer
:buffer
.#,loop >:cursor
:buffer
:cursor :buffer sub
string-reverse! .s
end
; define-function
#+end_src
***** .#2 .#8 .#16
#+begin_src cicada-nymph :tangle core.cn
: .#2 2 .# " " .s end ; define-function
: .#8 8 .# " " .s end ; define-function
: .#16 16 .# " " .s end ; define-function
#+end_src
***** test .#
#+begin_src cicada-nymph :tangle core-test.cn
: "* (testing) .#" .s .l
.s .l
0#111 0 .# .l
<< error
1#111 1 .# .l
>>
10#123 10 .# .l
10#0 10 .# .l
2#1000 2 .# .l
2#1111_1111 2 .# .l
16#f_f 16 .# .l
36#zzzz 36 .# .l
2#1111_1111 .#2 .l
8#123 .#8 .l
16#fff .#16 .l
; dup2 test-do
#+end_src
*** init,syntax-rule-set:basic-REPL
#+begin_src cicada-nymph :tangle core.cn
: init,syntax-rule-set:basic-REPL
<< -- >>
syntax-rule-set:*word-interpreter*
dup jo integer-string? jo string->integer syntax-rule:add
jo base#wild-integer-string? jo base#wild-integer-string->integer syntax-rule:add
end
; define-function
init,syntax-rule-set:basic-REPL
#+end_src
*** test REPL
#+begin_src cicada-nymph :tangle core-test.cn
: "* (testing) REPL" .s .l
0#111
0 0 power 1 mul
0 1 power 1 mul add
0 2 power 1 mul add
equal?
1#111
1 0 power 1 mul
1 1 power 1 mul add
1 2 power 1 mul add
equal? and
10#123
_1_0__#_1__2_3_
equal? and
_1_0__#_1__2_3_
10 0 power 3 mul
10 1 power 2 mul add
10 2 power 1 mul add
equal? and
2#1000
2#_1000_
equal? and
2#_1000_
2 0 power 0 mul
2 1 power 0 mul add
2 2 power 0 mul add
2 3 power 1 mul add
equal? and
2#1111_1111
2 0 power 1 mul
2 1 power 1 mul add
2 2 power 1 mul add
2 3 power 1 mul add
2 4 power 1 mul add
2 5 power 1 mul add
2 6 power 1 mul add
2 7 power 1 mul add
equal? and
16#f_f
16 0 power 15 mul
16 1 power 15 mul add
equal? and
100#111
100 0 power 1 mul
100 1 power 1 mul add
100 2 power 1 mul add
equal? and
64#zzz
64 0 power 35 mul
64 1 power 35 mul add
64 2 power 35 mul add
equal? and
36#zzzz
36 0 power 35 mul
36 1 power 35 mul add
36 2 power 35 mul add
36 3 power 35 mul add
equal? and test
; test-do
#+end_src
* jojo-compiler
*** jojo-compiler,dispatch-word :redefine:
#+begin_src cicada-nymph :tangle core.cn
: jojo-compiler,dispatch-word
<< jo, string[address, length], word[address, length] --
jo, string[address, length] >>
dup2 find-syntax if
apply
end
then
dup2 name-hash-table,find-jo if
xx|swap|x drop2
jojo-area,stay
end
then
"* (jojo-compiler) meets undefined word : " .s .s .l
global-naming-stack:delete-last-record
'jojo-compiler,dispatch-word,fail awake
; define-function
#+end_src
*** jojo-compiler,dispatch-word,fail
#+begin_src cicada-nymph :tangle core.cn
: jojo-compiler,dispatch-word,fail
"* (jojo-compiler,dispatch-word,fail)" .s .l
drop-syntax-stack
action,reset-the-stack
<< scope-stack-pointer -- >>
address scope-stack:*pointer* set
'undo-jojo-compiler awake
; define-function
#+end_src
*** jojo-compiler :redefine:
#+begin_src cicada-nymph :tangle core.cn
: jojo-compiler,loop
<< jo, string[address, length] -- >>
dup2 string:space? if
drop2
drop
end
then
dup2
string:word-tail
xx|swap|xx
string:word
jojo-compiler,dispatch-word
loop
; define-function
: jojo-compiler
<< jo, string[address, length] -- >>
>::string
>:jo
<< this is an ad hoc
>> local-variable-table,clear
scope-stack:*pointer* >:scope-stack-pointer
0 :scope-stack-pointer offset-record,set-name
0 :scope-stack-pointer offset-record,set-offset
scope-stack:*unit* address scope-stack:*pointer* add-set
:scope-stack-pointer
jo jojo-compiler,dispatch-word,fail
'jojo-compiler,dispatch-word,fail await
jojo-compiler:*syntax-rule-set* push-syntax-stack
:jo ::string jojo-compiler,loop
drop-syntax-stack
address scope-stack:*pointer* set
end
; define-function
#+end_src
* define-function
*** init,name-hash-table,by-link
* the function should be evaled right after
(define-function) is redefined
* be ware of
the interface of (name-hash-table,search)
* I simply implement it as a recursive function
#+begin_src cicada-nymph :tangle core.cn
: init,name-hash-table,by-link
<< link -- >>
>:link
:link zero? if
end
then
:link link->next-link recur
:link name-hash-table,record-jo,by-link
end
; define-function
#+end_src
*** n-string->buffer!
* this function return length
#+begin_src cicada-nymph :tangle core.cn
: n-string->buffer!,loop
<< string-1[address, length],
...
string-2[address, length],
buffer, n, cursor
-- length >>
>:cursor
>:n
>:buffer
:n zero? if
:buffer
:cursor :buffer sub
string-reverse!
swap drop
end
then
dup zero? if
drop2
:buffer
:n sub1
:cursor
loop
then
dup2 add sub1 get-byte :cursor set-byte
sub1
:buffer
:n
:cursor add1
loop
; define-function
: n-string->buffer!
<< string-1[address, length],
...
string-2[address, length],
buffer, n
-- length >>
over n-string->buffer!,loop
end
; define-function
#+end_src
*** test n-string->buffer!
#+begin_src cicada-nymph :tangle core-test.cn
: *test,buffer*
512 allocate-memory
; test-variable
: "* (testing) n-string->buffer!" .s .l
"/home"
"/xyh"
"/cicada"
*test,buffer* 3 n-string->buffer!
*test,buffer* swap
"/home/xyh/cicada"
string:equal? test
; test-do
#+end_src
*** undo-jojo-compiler
#+begin_src cicada-nymph :tangle core.cn
: undo-jojo-compiler
action,reset-the-stack
<< *string-area,current-free-address*
*jojo-area,current-free-address*
string[address, length] >>
" the following jojo is not made :" .s .l
":" .s
.s .l
";" .s .l
address *jojo-area,current-free-address* set
address *string-area,current-free-address* set
drop-syntax-stack
end
; define-function
#+end_src
*** define-function :redefine:
#+begin_src cicada-nymph :tangle core.cn
: define-function
<< string[address, length] -- >>
*string-area,current-free-address* xx|swap|x
*jojo-area,current-free-address* xx|swap|x
<< *string-area,current-free-address*
*jojo-area,current-free-address*
string[address, length] >>
jo undo-jojo-compiler
'undo-jojo-compiler await
dup2 >::string
::string string:word >::name
::string string:word-tail >::body
*explainer,function* 0
make-jo-head >:jo
:jo
::name string->name
global-naming-stack:record-jo
*jojo-area,current-free-address* >:old-address
:jo ::body jojo-compiler
*jojo-area,current-free-address*
:old-address sub *cell-size* div
:jo jo,set-length
drop2
drop
drop
end
; define-function
#+end_src
*** test function
#+begin_src cicada-nymph
: k 1 2 3 add add . end ; define-function
k
: k 1 2 3 end ; define-function
k add add .
<< error >>
: k no end ; define-function
#+end_src
* *to use the new naming mechanism*
*** note
* 這裏的函數需要處理 鏈 中的重複定義的 珠
重複定義者 只有很少的幾個
一是 jojo-compiler 以及相關的
一是 define-function
*** switch
#+begin_src cicada-nymph :tangle core.cn
*link* init,name-hash-table,by-link
basic-REPL
#+end_src
* fix syntax about local-variable
*** jojo-compiler-syntax:local-variable-get :redefine:
#+begin_src cicada-nymph :tangle core.cn
: jojo-compiler-syntax:local-variable-get
<< string[address, length], word[address, length] --
string[address, length] >>
dup2 string->name scope-stack:find if
jo instruction,local-variable,n-get
jojo-area,stay
<< offset >>
offset-record,get-offset
jojo-area,stay
<< number >>
count-front-colon
jojo-area,stay
end
then
"* (jojo-compiler-syntax:local-variable-get)" .s .l
" local-variable not bound : " .s
.s .l
'undo-jojo-compiler await
; define-function
#+end_src
*** jojo-compiler-syntax:local-variable-set :redefine:
#+begin_src cicada-nymph :tangle core.cn
: jojo-compiler-syntax:local-variable-set
<< string[address, length], word[address, length] --
string[address, length] >>
string:byte-tail
>::local-variable-name
::local-variable-name count-front-colon >:number
::local-variable-name string->name >:name
:name scope-stack:find if
jo instruction,local-variable,n-set
jojo-area,stay
<< offset >>
offset-record,get-offset
jojo-area,stay
:number
jojo-area,stay
end
then
scope-stack:get-current-offset >:current-offset
:current-offset
scope-stack:*pointer*
offset-record,set-offset
:name
scope-stack:*pointer*
offset-record,set-name
scope-stack:*unit* address scope-stack:*pointer* add-set
jo instruction,literal
jojo-area,stay
:number
jojo-area,stay
jo allocate-local-variable
jojo-area,stay
jo instruction,local-variable,n-set
jojo-area,stay
:current-offset
jojo-area,stay
:number
jojo-area,stay
end
; define-function
#+end_src
*** jojo-compiler-syntax:if :redefine:
#+begin_src cicada-nymph :tangle core.cn
: jojo-compiler-syntax:if
<< jo, string[address, length], literal-word:if --
scope-stack-pointer,
address,
jo, string[address, length] >>
drop2
>::string
>:jo
jo instruction,false?branch
jojo-area,stay
scope-stack:*pointer*
*jojo-area,current-free-address*
:jo
::string
0 jojo-area,stay
end
; define-function
#+end_src
*** jojo-compiler-syntax:else :redefine:
#+begin_src cicada-nymph :tangle core.cn
: jojo-compiler-syntax:else
<< scope-stack-pointer,
address,
jo, string[address, length], literal-word:else --
scope-stack-pointer,
address,
jo, string[address, length] >>
drop2
>::string
>:jo
>:address
>:scope-stack-pointer
:scope-stack-pointer address scope-stack:*pointer* set
jo instruction,branch
jojo-area,stay
scope-stack:*pointer*
*jojo-area,current-free-address*
:jo
::string
0 jojo-area,stay
<<
set offset of (instruction,false?branch)
over (instruction,branch) and its offset
>>
*jojo-area,current-free-address* :address sub
*cell-size* div
:address set
end
; define-function
#+end_src
*** jojo-compiler-syntax:then :redefine:
#+begin_src cicada-nymph :tangle core.cn
: jojo-compiler-syntax:then
<< scope-stack-pointer,
address,
jo, string[address, length], literal-word:then --
jo, string[address, length] >>
drop2
>::string
>:jo
>:address
>:scope-stack-pointer
*jojo-area,current-free-address* :address sub
*cell-size* div
:address set
:jo
::string
end
; define-function
#+end_src
*** more,syntax-rule-set:jojo-compiler
#+begin_src cicada-nymph :tangle core.cn
: more,syntax-rule-set:jojo-compiler
<< -- >>
jojo-compiler:*syntax-rule-set*
jo local-variable-get-word?
jo jojo-compiler-syntax:local-variable-get
syntax-rule:add
jojo-compiler:*syntax-rule-set*
jo local-variable-set-word?
jo jojo-compiler-syntax:local-variable-set
syntax-rule:add
jojo-compiler:*syntax-rule-set*
dup jo literal-word:if? jo jojo-compiler-syntax:if syntax-rule:add
dup jo literal-word:else? jo jojo-compiler-syntax:else syntax-rule:add
jo literal-word:then? jo jojo-compiler-syntax:then syntax-rule:add
end
; define-function
more,syntax-rule-set:jojo-compiler
#+end_src
* argument-stack:print
*** argument-stack:print
#+begin_src cicada-nymph :tangle core.cn
: argument-stack:print,loop
<< address, counter -- >>
dup zero? if
drop2
end
then
sub1 swap
dup get .
*cell-size* add
swap
loop
; define-function
: argument-stack:print
<< -- >>
snapshot-the-stack-pointer
*the-stack-pointer-snapshot*
*the-stack* greater-or-equal? if
*the-stack* << address as return value >>
*the-stack-pointer-snapshot* *the-stack* sub
*cell-size* div << counter as return value >>
argument-stack:print,loop
end
then
"below the stack " .s
end
; define-function
#+end_src
*** argument-stack:pretty-print
#+begin_src cicada-nymph :tangle core.cn
: argument-stack:pretty-print
<< -- >>
snapshot-the-stack-pointer
.l
" * " .s
*the-stack-pointer-snapshot*
*the-stack* sub
<< ad hoc for the BUG of div >>
dup negative? if
negate
*cell-size* div
negate
else
*cell-size* div
then
.i
" * " .s
" -- " .s
argument-stack:print
"--" .s
.l
end
; define-function
#+end_src
* define-variable,with-tos
*** define-variable,with-tos :redefine:
* not undo is needed for define-variable,with-tos
#+begin_src cicada-nymph :tangle core.cn
: define-variable,with-tos
<< value, string[address, length] -- >>
>::string
>:value
::string string:word >::name
*explainer,variable* 0
make-jo-head >:jo
:jo
::name string->name
global-naming-stack:record-jo
1 :jo jo,set-length
:value jojo-area,stay
end
; define-function
#+end_src
*** test define-variable,with-tos
#+begin_src cicada-nymph :tangle core-test.cn
233
: *three*
; test-variable,with-tos
: add-three
*three* add
end
; test-function
: fix-*three*
3
address *three*
set
end
; test-function
: "* (testing) define-variable,with-tos" .s .l
1 add-three
234 equal?
fix-*three* 1 add-three
4 equal? and test
; test-do
#+end_src
* alias
*** note
* there shall be no way to know a naming is an alias or not
*** alias
#+begin_src cicada-nymph :tangle core.cn
: alias
<< alias[address, length], name[address, length] -- >>
>::name >::alias
::name name-hash-table,find-jo if
else
"* (alias) fail" .s .l
" because can not find name in name-hash-table" .s .l
" alias : " .s ::alias .s .l
" name : " .s ::name .s .l
end
then
>:jo
:jo
::alias string->name
global-naming-stack:record-jo
end
; define-function
#+end_src
*** test alias
#+begin_src cicada-nymph :tangle core-test.cn
: "* (testing) alias" .s .l
"adba" "add" alias
1 2 adba
3 equal? test
; test-do
<< error
"ab" "ad" alias
>>
#+end_src
* jojo-compiler-syntax:square-bar
*** string:find-word
#+begin_src cicada-nymph :tangle core.cn
: string:find-word
<< string[address, length], word[address, length]
-- sub-string[address, length], true
-- false >>
xx|over|xx string:space? if
drop2 drop2
false
end
then
xx|over|xx string:word
xx|over|xx string:equal? if
drop2
true
end
then
xx|swap|xx string:word-tail
xx|swap|xx
loop
; define-function
#+end_src
*** test string:find-word
#+begin_src cicada-nymph :tangle core-test.cn
: "* (testing) string:find-word" .s .l
"111 222 333" "222" string:find-word if
" 222 333" string:equal? test
else
false test
then
"111 222 333" "444" string:find-word if
.l .s .l
false test
else
true test
then
"111 222 [] 333" "[" string:find-word if
" [] 333" string:equal? test
else
false test
then
; test-do
#+end_src
*** note side-effect
* side-effect on function [unnamed or named] is actually not so needed
for function is mainly used to encode algorithm
* but side-effect on function is always possible when needed
*** note scope of named-local-variable
* in named function or unnamed function
the scope of named-local-variable is linear
*** literal-word:square-bar?
#+begin_src cicada-nymph :tangle core.cn
: literal-word:square-bar?
<< word[address, length] -- bool >>
"[" string:equal?
end
; define-function
#+end_src
*** literal-word:square-ket?
#+begin_src cicada-nymph :tangle core.cn
: literal-word:square-ket?
<< word[address, length] -- bool >>
"]" string:equal?
end
; define-function
#+end_src
*** note memory usage
* for the array can be nested
we must allocate the memory in place
a branch is there helping us to achieve this
* [dup drop end]
|-------------------|
| branch |
| offset to jo |
|-------------------|
| |
|-------------------|
| dup |
| drop |
| end |
|-------------------|
| literal |
| address of the jo |
|-------------------|
*** jojo-compiler-syntax:square-bar
#+begin_src cicada-nymph :tangle core.cn
: jojo-compiler-syntax:square-bar
<< jo, string[address, length], literal-word:square-bar --
scope-stack-pointer,
offset-address,
new-jo,
jo, string[address, length] >>
drop2
>::string
>:jo
jo instruction,branch
jojo-area,stay
*jojo-area,current-free-address* >:offset-address
0 jojo-area,stay
*explainer,function* 0
make-jo-head >:new-jo
scope-stack:*pointer* >:scope-stack-pointer
0
:scope-stack-pointer
offset-record,set-name
0
:scope-stack-pointer
offset-record,set-offset
scope-stack:*unit* address scope-stack:*pointer* add-set
:scope-stack-pointer
:offset-address
:new-jo
:jo
::string
end
; define-function
#+end_src
*** jojo-compiler-syntax:square-ket
#+begin_src cicada-nymph :tangle core.cn
: jojo-compiler-syntax:square-ket
<< scope-stack-pointer,
offset-address,
new-jo,
jo, string[address, length], literal-word:square-ket --
jo, string[address, length] >>
drop2
>::string
>:jo
>:new-jo
>:offset-address
>:scope-stack-pointer
:scope-stack-pointer address scope-stack:*pointer* set
*jojo-area,current-free-address*
:offset-address sub
*cell-size* div
:offset-address set
jo instruction,literal
jojo-area,stay
:new-jo
jojo-area,stay
:jo
::string
end
; define-function
#+end_src
*** more,syntax-rule-set:jojo-compiler
#+begin_src cicada-nymph :tangle core.cn
: more,syntax-rule-set:jojo-compiler
<< -- >>
jojo-compiler:*syntax-rule-set*
dup jo literal-word:square-bar? jo jojo-compiler-syntax:square-bar syntax-rule:add
jo literal-word:square-ket? jo jojo-compiler-syntax:square-ket syntax-rule:add
end
; define-function
more,syntax-rule-set:jojo-compiler
#+end_src
*** test square-bar & square-ket by factorial
#+begin_src cicada-nymph :tangle core-test.cn
: testing-square-bar
["testing square-bar & square-ket" end]
end
; test-function
: "* (testing) square-bar & square-ket" .s .l
testing-square-bar apply
"testing square-bar & square-ket"
string:equal? test
; test-do
: apply-factorial
<< number -- number >>
[dup
one? if
end
then
dup sub1 recur
mul
end] apply
end
; test-function
: "* (testing) square-bar & square-ket by factorial" .s .l
1 apply-factorial 1 equal?
2 apply-factorial 2 equal? and
3 apply-factorial 6 equal? and
4 apply-factorial 24 equal? and
5 apply-factorial 120 equal? and
6 apply-factorial 720 equal? and test
end
; test-do
#+end_src
* jojo-compiler-syntax:name
*** jojo-compiler-syntax:name
#+begin_src cicada-nymph :tangle core.cn
: jojo-compiler-syntax:name
<< string[address, length], word[address, length] --
string[address, length] >>
drop2
jo instruction,literal
jojo-area,stay
dup2
string:word
string->name
jojo-area,stay
string:word-tail
end
; define-function
#+end_src
*** more,syntax-rule-set:jojo-compiler
#+begin_src cicada-nymph :tangle core.cn
: more,syntax-rule-set:jojo-compiler
<< -- >>
jojo-compiler:*syntax-rule-set*
["name" string:equal? end] jo jojo-compiler-syntax:name
syntax-rule:add
end
; define-function
more,syntax-rule-set:jojo-compiler
#+end_src
*** test jojo-compiler-syntax:name
#+begin_src cicada-nymph :tangle core-test.cn
: jojo-compiler-syntax:name,test
<< -- string[address, length] >>
name test-name name->string
end
; test-function
: "* (testing) jojo-compiler-syntax:name" .s .l
jojo-compiler-syntax:name,test
"test-name" string:equal? test
; test-do
#+end_src
* jojo-compiler-syntax:base#wild-integer-string
*** jojo-compiler-syntax:base#wild-integer-string
#+begin_src cicada-nymph :tangle core.cn
: jojo-compiler-syntax:base#wild-integer-string
<< string[address, length], word[address, length] --
string[address, length] >>
jo instruction,literal
jojo-area,stay
base#wild-integer-string->integer
jojo-area,stay
end
; define-function
#+end_src
*** more,syntax-rule-set:jojo-compiler
#+begin_src cicada-nymph :tangle core.cn
: more,syntax-rule-set:jojo-compiler
<< -- >>
jojo-compiler:*syntax-rule-set*
jo base#wild-integer-string?
jo jojo-compiler-syntax:base#wild-integer-string
syntax-rule:add
end
; define-function
more,syntax-rule-set:jojo-compiler
#+end_src
* word-interpreter-syntax
*** jo :syntax:
***** word-interpreter-syntax:jo
#+begin_src cicada-nymph :tangle core.cn
: word-interpreter-syntax:jo
<< literal-word:jo -- jo >>
drop2
read-word
>::word
::word name-hash-table,find-jo if
end
then
"* (word-interpreter-syntax:jo) meet undefined word after jo : " .s ::word .s .l
end
; define-function
#+end_src
***** more,syntax-rule-set:basic-REPL
#+begin_src cicada-nymph :tangle core.cn
: more,syntax-rule-set:basic-REPL
<< -- >>
syntax-rule-set:*word-interpreter*
["bye" string:equal? end] jo word-interpreter-syntax:bye
syntax-rule:add
syntax-rule-set:*word-interpreter*
["jo" string:equal? end] jo word-interpreter-syntax:jo
syntax-rule:add
end
; define-function
more,syntax-rule-set:basic-REPL
#+end_src
*** if & else & then :syntax:
***** note ending jo
* you do not need to use ending jo
in code blocks formed by if else then
because in a REPL
things are different from function body
and there is no such thing as
the end of a function body in the REPL
***** note (end) in REPL
* when use (end) in REPL
nothing will happen
this is because (word-interpreter) calls (end)
and the jojo (word-interpreter) is pop out of return-stack
just like meet (end) in the function-body of (word-interpreter)
***** word-interpreter-syntax:if,meet-true
#+begin_src cicada-nymph :tangle core.cn
: word-interpreter-syntax:if,meet-true,else
<< -- >>
read-word
"then" string:equal? if
end
then
loop
; define-function
: word-interpreter-syntax:if,meet-true
<< -- >>
read-word
dup2 "then" string:equal? if
drop2
end
then
dup2 "else" string:equal? if
drop2
word-interpreter-syntax:if,meet-true,else
end
then
word-interpreter
loop
; define-function
#+end_src
***** word-interpreter-syntax:if,meet-false
#+begin_src cicada-nymph :tangle core.cn
: word-interpreter-syntax:if,meet-false,else
<< -- >>
read-word
dup2 "then" string:equal? if
drop2
end
then
word-interpreter
loop
; define-function
: word-interpreter-syntax:if,meet-false
<< -- >>
read-word
dup2 "then" string:equal? if
drop2
end
then
dup2 "else" string:equal? if
drop2
word-interpreter-syntax:if,meet-false,else
end
then
drop2
loop
; define-function
#+end_src
***** word-interpreter-syntax:if
#+begin_src cicada-nymph :tangle core.cn
: word-interpreter-syntax:if
<< bool, literal-word:if -- >>
drop2 if
word-interpreter-syntax:if,meet-true
else
word-interpreter-syntax:if,meet-false
then
end
; define-function
#+end_src
***** syntax-rule:add to syntax-rule-set:*word-interpreter*
#+begin_src cicada-nymph :tangle core.cn
syntax-rule-set:*word-interpreter*
jo literal-word:if? jo word-interpreter-syntax:if
syntax-rule:add
#+end_src
***** test word-interpreter-syntax:if & else & then
#+begin_src cicada-nymph :tangle core-test.cn
: "* (testing) word-interpreter-syntax:if & else & then" .s .l
1
one? if
111
then
111 equal? test
0
one? if
111
else
666
then
666 equal? test
; test-do
#+end_src
*** *circular-string-area*
***** note
* no length in the area anymore
[not like the string-area]
* and ending each string here with a 0
***** allocate-memory
#+begin_src cicada-nymph :tangle core.cn
1024 1024 mul
: *circular-string-area,size*
; define-variable,with-tos
*circular-string-area,size* allocate-memory
: *circular-string-area*
; define-variable,with-tos
*circular-string-area*
: *circular-string-area,current-free-address*
; define-variable,with-tos
#+end_src
*** double-quote :syntax:
***** circular-string-area,stay
#+begin_src cicada-nymph :tangle core.cn
: circular-string-area,stay
<< string[address, length] -- >>
dup *circular-string-area,current-free-address* add
*circular-string-area,size* *circular-string-area* add
greater-or-equal? if
*circular-string-area*
address *circular-string-area,current-free-address* set
then
tuck
*circular-string-area,current-free-address*
string->buffer!
address *circular-string-area,current-free-address*
add-set
0 *circular-string-area,current-free-address*
set-byte
1 address *circular-string-area,current-free-address*
add-set
end
; define-function
#+end_src
***** word-interpreter-syntax:double-quote
* in ASCII encode double-quote is 34
#+begin_src cicada-nymph :tangle core.cn
: word-interpreter-syntax:double-quote,loop
<< cursor -- cursor >>
read-byte
dup 34 equal? if
drop
end
then
over set-byte
add1
loop
; define-function
: word-interpreter-syntax:double-quote
<< literal-word:double-quote -- string[address, length] >>
drop2
1024 2 mul allocate-local-memory >:buffer
:buffer
word-interpreter-syntax:double-quote,loop
>:cursor
*circular-string-area,current-free-address* >:address
:buffer
:cursor :buffer sub dup >:length
circular-string-area,stay
:address
:length
end
; define-function
#+end_src
***** syntax-rule:add to syntax-rule-set:*word-interpreter*
#+begin_src cicada-nymph :tangle core.cn
syntax-rule-set:*word-interpreter*
jo literal-word:double-quote? jo word-interpreter-syntax:double-quote
syntax-rule:add
#+end_src
***** test word-interpreter-syntax:double-quote
#+begin_src cicada-nymph :tangle core-test.cn
: "* (testing) word-interpreter-syntax:double-quote" .s .l
1
one? if
"111"
then
"111" string:equal? test
0
one? if
"111"
else
"___"
then
"___" string:equal? test
; test-do
#+end_src
*** address :syntax:
***** word-interpreter-syntax:address
#+begin_src cicada-nymph :tangle core.cn
: word-interpreter-syntax:address
<< literal-word:address -- address >>
drop2
read-word
>::word
::word name-hash-table,find-jo if
else
"* (word-interpreter-syntax:address) meet undefined word : " .s ::word .s .l
end
then
>:jo
:jo variable-jo? if
else
"* (word-interpreter-syntax:address) meet a not variable-jo : " .s ::word .s .l
end
then
:jo *cell-size* add
end
; define-function
#+end_src
***** syntax-rule:add to syntax-rule-set:*word-interpreter*
#+begin_src cicada-nymph :tangle core.cn
syntax-rule-set:*word-interpreter*
jo literal-word:address?
jo word-interpreter-syntax:address
syntax-rule:add
#+end_src
***** test word-interpreter-syntax:address
#+begin_src cicada-nymph :tangle core-test.cn
0
: word-interpreter-syntax:*testing-variable*
; test-variable,with-tos
: "* (testing) word-interpreter-syntax:address" .s .l
666
address word-interpreter-syntax:*testing-variable* set
word-interpreter-syntax:*testing-variable*
666 equal? test
; test-do
<< error
address kkk
>>
#+end_src
*** literal-word:name?
#+begin_src cicada-nymph :tangle core.cn
: literal-word:name?
<< word[address, length] -- bool >>
"name" string:equal?
end
; define-function
#+end_src
*** name :syntax:
***** word-interpreter-syntax:name
#+begin_src cicada-nymph :tangle core.cn
: word-interpreter-syntax:name
<< literal-word:name -- name >>
drop2
read-word
>::word
::word string->name
end
; define-function
#+end_src
***** syntax-rule:add to syntax-rule-set:*word-interpreter*
#+begin_src cicada-nymph :tangle core.cn
syntax-rule-set:*word-interpreter*
jo literal-word:name?
jo word-interpreter-syntax:name
syntax-rule:add
#+end_src
***** test word-interpreter-syntax:name
#+begin_src cicada-nymph :tangle core-test.cn
: "* (testing) word-interpreter-syntax:name" .s .l
name add
name->string "add" string:equal? test
name word-interpreter-syntax:*testing-variable*
name->string "word-interpreter-syntax:*testing-variable*" string:equal? test
name kkk
name->string "kkk" string:equal? test
; test-do
#+end_src
*** quote
***** word-interpreter-syntax:quote
#+begin_src cicada-nymph :tangle core.cn
: word-interpreter-syntax:quote
<< quote-word -- name >>
string:byte-tail string->name
end
; define-function
#+end_src
***** syntax-rule:add to syntax-rule-set:*word-interpreter*
#+begin_src cicada-nymph :tangle core.cn
syntax-rule-set:*word-interpreter*
jo quote-word?
jo word-interpreter-syntax:quote
syntax-rule:add
#+end_src
***** test word-interpreter-syntax:quote
#+begin_src cicada-nymph :tangle core-test.cn
: "* (testing) word-interpreter-syntax:name" .s .l
'add
name->string "add" string:equal? test
'kkk
name->string "kkk" string:equal? test
; test-do
#+end_src
* *a little test*
*** nested comment
#+begin_src cicada-nymph :tangle core-test.cn
: "* (testing) nested comment in REPL" .s .l
1 << 2 3 4 >> 5
1 << 2 << 3 >> 4 >> 5
5 equal?
1 equal? add
5 equal? add
1 equal? add test
end
; test-do
: nested-comment-function-body
1 << 2 3 4 >> 5
1 << 2 << 3 >> 4 >> 5
5 equal?
1 equal? add
5 equal? add
1 equal? add test
end
; test-function
: "* (testing) nested comment in function body" .s .l
nested-comment-function-body
end
; test-do
#+end_src
*** return structured value
#+begin_src cicada-nymph :tangle core-test.cn
: callee
<< -- string[address, length] >>
512 allocate-conjugate-local-memory >:buffer
"(callee ^-^) " >:length >:address
:address :length
:buffer
string->buffer!
:buffer :length
end
; test-function
: caller
<< -- string[address, length] >>
512 allocate-local-memory >:buffer
"(caller O.o) " >:length >:address
:address :length
:buffer
string->buffer!
:buffer :length >::caller-string-1
callee >::callee-string
512 allocate-local-memory >:buffer
"(caller o.O) " >:length >:address
:address :length
:buffer
string->buffer!
:buffer :length >::caller-string-2
512 allocate-local-memory >:buffer
::caller-string-1
::callee-string
::caller-string-2
:buffer
3 n-string->buffer! >:length
:buffer
:length
end
; test-function
: "* (testing) return structured value" .s .l
caller
"(caller O.o) (callee ^-^) (caller o.O) "
string:equal? test
; test-do
#+end_src
* syntax-rule-set & syntax-rule
*** test endianness of n-get & n-set
* big-endian is used
in memory
| value-1 |
| value-2 |
| value-3 |
on stack
<< value-1, value-2, value-3 >>
#+begin_src cicada-nymph :tangle core-test.cn
3 *cell-size* mul allocate-memory
: *t*
; test-variable,with-tos
: "* (testing) endianness of n-get & n-set" .s .l
1 2 3 *t* 3 n-set
<< re-occur when geting through >>
*t* get
1 equal?
*t* *cell-size* add get
2 equal? and
*t* *cell-size* 2 mul add get
3 equal? and test
*t* 3 n-get
3 equal? test
2 equal? test
1 equal? test
; test-do
#+end_src
*** syntax-rule-set:list
* 最後寫到規則集合裏的 被最先打印出來
* 下面的打印方式 看似有些不簡潔
是因爲 我還沒有 integer->string 這樣的函數
[因爲 沒有對字符串的動態內存管理]
#+begin_src cicada-nymph :tangle core.cn
: syntax-rule-set:list,loop
<< syntax-rule-set: cursor, counter -- >>
xx|over|x equal? if
drop drop2
end
then
" * " .s
"(" .s
add1 dup .i
")" .s .l
swap
dup syntax-rule:*unit* sub syntax-rule:get-predicate
" " .s jo,find-name if name->string else " unnamed jo" then .s .l
dup syntax-rule:*unit* sub syntax-rule:get-function
" " .s jo,find-name if name->string else " unnamed jo" then .s .l
*cell-size* sub *cell-size* sub
swap
loop
; define-function
: syntax-rule-set:list
<< syntax-rule-set -- >>
dup syntax-rule-set:get-border
0 syntax-rule-set:list,loop
end
; define-function
#+end_src
*** syntax-rule:sub
* firstly
in (syntax-rule:sub,loop)
cursor move from border down to address of syntax-rule-set
secondly
in (syntax-rule:sub,move)
cursor move from founded place up to border
#+begin_src cicada-nymph :tangle core.cn
: syntax-rule:sub,move-one
<< cursor -- >>
>:cursor
:cursor 2 n-get
:cursor *cell-size* 2 mul sub
2 n-set
end
; define-function
: syntax-rule:sub,move
<< syntax-rule-set: cursor -- >>
>:cursor
>:syntax-rule-set
:syntax-rule-set syntax-rule-set:get-border >:border
:cursor :border equal? if
:border *cell-size* 2 mul sub
:syntax-rule-set
syntax-rule-set:set-border
end
then
:cursor syntax-rule:sub,move-one
:syntax-rule-set
:cursor *cell-size* 2 mul add
loop
; define-function
: syntax-rule:sub,loop
<< syntax-rule-set: syntax-rule[predicate, function], cursor -- >>
>:cursor
>::syntax-rule
>:syntax-rule-set
:cursor :syntax-rule-set equal? if
end
then
::syntax-rule
:cursor syntax-rule:*unit* sub syntax-rule:get
equal2? if
:syntax-rule-set :cursor
syntax-rule:sub,move
end
then
:syntax-rule-set
::syntax-rule
:cursor *cell-size* 2 mul sub
loop
; define-function
: syntax-rule:sub
<< syntax-rule-set: syntax-rule[predicate, function] -- >>
x|over|xx syntax-rule-set:get-border
syntax-rule:sub,loop
end
; define-function
#+end_src
*** test
#+begin_src cicada-nymph
syntax-rule-set:*word-interpreter* syntax-rule-set:list
syntax-rule-set:*word-interpreter*
jo literal-word:address?
jo word-interpreter-syntax:address
syntax-rule:add
syntax-rule-set:*word-interpreter*
jo literal-word:double-quote?
jo word-interpreter-syntax:double-quote
syntax-rule:add
syntax-rule-set:*word-interpreter* syntax-rule-set:list
syntax-rule-set:*word-interpreter*
jo literal-word:address?
jo word-interpreter-syntax:address
syntax-rule:sub
syntax-rule-set:*word-interpreter* syntax-rule-set:list
syntax-rule-set:*word-interpreter*
jo literal-word:double-quote?
jo word-interpreter-syntax:double-quote
syntax-rule:sub
syntax-rule-set:*word-interpreter* syntax-rule-set:list
#+end_src
*** syntax-rule-set:mixin
* the order matters
#+begin_src cicada-nymph :tangle core.cn
: syntax-rule-set:mixin,loop
<< base-syntax-rule-set: border, cursor -- >>
dup2 equal? if
drop2
drop
end
then
dup syntax-rule:get >::syntax-rule
x|over|xx ::syntax-rule syntax-rule:add
syntax-rule:*unit* add
loop
; define-function
: syntax-rule-set:mixin
<< base-syntax-rule-set: syntax-rule-set -- >>
dup syntax-rule-set:get-border swap
syntax-rule-set:mixin,loop
end
; define-function
#+end_src
*** syntax-rule-set:mixout
#+begin_src cicada-nymph :tangle core.cn
: syntax-rule-set:mixout,loop
<< base-syntax-rule-set: border, cursor -- >>
dup2 equal? if
drop2
drop
end
then
dup syntax-rule:get >::syntax-rule
x|over|xx ::syntax-rule syntax-rule:sub
syntax-rule:*unit* add
loop
; define-function
: syntax-rule-set:mixout
<< base-syntax-rule-set: syntax-rule-set -- >>
dup syntax-rule-set:get-border swap
syntax-rule-set:mixout,loop
end
; define-function
#+end_src
* stack-REPL
*** note
* print argument-stack in every loop
*** stack-REPL
#+begin_src cicada-nymph :tangle core.cn
: stack-REPL,loop
<< unknown -- unknown >>
read-word
word-interpreter
argument-stack:pretty-print
loop
; define-function
: stack-REPL
<< unknown -- unknown >>
jo bye,basic-REPL
'bye,basic-REPL await
syntax-rule-set:*word-interpreter* push-syntax-stack
stack-REPL,loop
end
; define-function
#+end_src
* eval-string
*** note
* (eval-string) is implemented by doing side-effect on reading-stack
this is because syntax extension system is implemented by reader-macro
* by implementing (eval-string) this way
i can easily change the syntax be used to eval a string
*** eval-string
#+begin_src cicada-nymph :tangle core.cn
: eval-string,loop
<< unknown -- unknown >>
tos-reading-stack string:space? if
end
then
read-word
word-interpreter
loop
; define-function
: eval-string
<< string[address, length] -- unknown >>
push-reading-stack
eval-string,loop
drop-reading-stack
end
; define-function
#+end_src
*** test eval-string
#+begin_src cicada-nymph :tangle core-test.cn
: "* (testing) eval-string" .s .l
"1 2 3 add add" eval-string 6 equal? test
" 1 2 3 add add " eval-string 6 equal? test
" k
1 2 3 add add
end
"
"define-function k" eval-string 6 equal? test
k 6 equal? test
; test-do
#+end_src
* define-variable
*** note string allocation
* string should be allocated to a static area
instead of dynamic area like *circular-string-area*
thus we have
(syntax,double-quote,define-variable)
*** syntax,double-quote,define-variable
* in ASCII encode double-quote is 34
#+begin_src cicada-nymph :tangle core.cn
: syntax,double-quote,define-variable,loop
<< cursor -- cursor >>
read-byte
dup 34 equal? if
drop
end
then
over set-byte
add1
loop
; define-function
: syntax,double-quote,define-variable
<< literal-word:double-quote -- string[address, length] >>
drop2
1024 2 mul allocate-local-memory >:buffer
:buffer
syntax,double-quote,define-variable,loop
>:cursor
:buffer
:cursor :buffer sub
make-string
end
; define-function
#+end_src
*** define-variable
#+begin_src cicada-nymph :tangle core.cn
: define-variable
<< string[address, length] -- >>
>::string
::string string:word >::name
::string string:word-tail >::body
snapshot-the-stack-pointer
*the-stack-pointer-snapshot* >:old-snapshot
syntax-rule-set:*word-interpreter*
jo literal-word:double-quote?
jo syntax,double-quote,define-variable
syntax-rule:add
::body eval-string
syntax-rule-set:*word-interpreter*
jo literal-word:double-quote?
jo syntax,double-quote,define-variable
syntax-rule:sub
snapshot-the-stack-pointer
*the-stack-pointer-snapshot* >:new-snapshot
:new-snapshot :old-snapshot sub
dup negative? if
negate *cell-size* div
"* (define-variable) fail to define variable : " .s ::name .s .l
" because after eval the following body" .s .l
" the stack is " .s .i " below what it use to be" .s .l
::body .s .l
end
then
dup zero? if
drop
"* (define-variable) fail to define variable : " .s ::name .s .l
" because after eval the following body" .s .l
" the stack is still where it use to be" .s .l
::body .s .l
end
then
*cell-size* div >:length
::name make-string >::name
::name *link* 0
make-link >:link
:link address *link* set
*explainer,variable* 0
make-jo-head >:jo
:jo :link link,set-jo
:link name-hash-table,record-jo,by-link
:length
:jo jo,set-length
*jojo-area,current-free-address*
:length
n-set
:length *cell-size* mul
address *jojo-area,current-free-address*
add-set
end
; define-function
#+end_src
*** test
#+begin_src cicada-nymph
: define-variable:*testing-numbers*
1 2 3
; define-variable
define-variable:*testing-numbers* . . . << 3 2 1 >>
address define-variable:*testing-numbers* get . << 1 >>
: define-variable:*testing-string*
"define-variable"
; define-variable
define-variable:*testing-string* .s << define-variable >>
<< error >>
: kkk
1 . 2 . 3 .
; define-variable
<< error >>
1 2 3
: kkk
. . .
; define-variable
#+end_src
* system misc
*** note linux
*** init-syscall-number :32bit:
#+begin_src cicada-nymph :tangle core.cn
*cell-size* 4 equal? if
5 : syscall-number:*open* ; define-variable,with-tos
6 : syscall-number:*close* ; define-variable,with-tos
3 : syscall-number:*read* ; define-variable,with-tos
4 : syscall-number:*write* ; define-variable,with-tos
9 : syscall-number:*link* ; define-variable,with-tos
10 : syscall-number:*unlink* ; define-variable,with-tos
39 : syscall-number:*mkdir* ; define-variable,with-tos
40 : syscall-number:*rmdir* ; define-variable,with-tos
141 : syscall-number:*getdents* ; define-variable,with-tos
220 : syscall-number:*getdents64* ; define-variable,with-tos
106 : syscall-number:*stat* ; define-variable,with-tos
1 : syscall-number:*exit* ; define-variable,with-tos
43 : syscall-number:*times* ; define-variable,with-tos
20 : syscall-number:*getpid* ; define-variable,with-tos
183 : syscall-number:*getcwd* ; define-variable,with-tos
12 : syscall-number:*chdir* ; define-variable,with-tos
then
#+end_src
*** init-syscall-number :64bit:
#+begin_src cicada-nymph :tangle core.cn
*cell-size* 8 equal? if
2 : syscall-number:*open* ; define-variable,with-tos
3 : syscall-number:*close* ; define-variable,with-tos
0 : syscall-number:*read* ; define-variable,with-tos
1 : syscall-number:*write* ; define-variable,with-tos
86 : syscall-number:*link* ; define-variable,with-tos
87 : syscall-number:*unlink* ; define-variable,with-tos
83 : syscall-number:*mkdir* ; define-variable,with-tos
84 : syscall-number:*rmdir* ; define-variable,with-tos
78 : syscall-number:*getdents* ; define-variable,with-tos
217 : syscall-number:*getdents64* ; define-variable,with-tos
4 : syscall-number:*stat* ; define-variable,with-tos
60 : syscall-number:*exit* ; define-variable,with-tos
100 : syscall-number:*times* ; define-variable,with-tos
39 : syscall-number:*getpid* ; define-variable,with-tos
79 : syscall-number:*getcwd* ; define-variable,with-tos
80 : syscall-number:*chdir* ; define-variable,with-tos
then
#+end_src
*** error-code->string
#+begin_src cicada-nymph :tangle core.cn
: error-code->string
<< error-code -- string[address, length] >>
dup -1 equal? if drop << EPERM >> "Operation not permitted " end then
dup -2 equal? if drop << ENOENT >> "No such file or directory " end then
dup -3 equal? if drop << ESRCH >> "No such process " end then
dup -4 equal? if drop << EINTR >> "Interrupted system call " end then
dup -5 equal? if drop << EIO >> "I/O error " end then
dup -6 equal? if drop << ENXIO >> "No such device or address " end then
dup -7 equal? if drop << E2BIG >> "Argument list too long " end then
dup -8 equal? if drop << ENOEXEC >> "Exec format error " end then
dup -9 equal? if drop << EBADF >> "Bad file number " end then
dup -10 equal? if drop << ECHILD >> "No child processes " end then
dup -11 equal? if drop << EAGAIN >> "Try again " end then
dup -12 equal? if drop << ENOMEM >> "Out of memory " end then
dup -13 equal? if drop << EACCES >> "Permission denied " end then
dup -14 equal? if drop << EFAULT >> "Bad address " end then
dup -15 equal? if drop << ENOTBLK >> "Block device required " end then
dup -16 equal? if drop << EBUSY >> "Device or resource busy " end then
dup -17 equal? if drop << EEXIST >> "File exists " end then
dup -18 equal? if drop << EXDEV >> "Cross-device link " end then
dup -19 equal? if drop << ENODEV >> "No such device " end then
dup -20 equal? if drop << ENOTDIR >> "Not a directory " end then
dup -21 equal? if drop << EISDIR >> "Is a directory " end then
dup -22 equal? if drop << EINVAL >> "Invalid argument " end then
dup -23 equal? if drop << ENFILE >> "File table overflow " end then
dup -24 equal? if drop << EMFILE >> "Too many open files " end then
dup -25 equal? if drop << ENOTTY >> "Not a typewriter " end then
dup -26 equal? if drop << ETXTBSY >> "Text file busy " end then
dup -27 equal? if drop << EFBIG >> "File too large " end then
dup -28 equal? if drop << ENOSPC >> "No space left on device " end then
dup -29 equal? if drop << ESPIPE >> "Illegal seek " end then
dup -30 equal? if drop << EROFS >> "Read-only file system " end then
dup -31 equal? if drop << EMLINK >> "Too many links " end then
dup -32 equal? if drop << EPIPE >> "Broken pipe " end then
dup -33 equal? if drop << EDOM >> "Math argument out of domain of func " end then
dup -34 equal? if drop << ERANGE >> "Math result not representable " end then
"unknow error-code : " .s .i .l
"* (error-code->string) fail" << to balance the argument-stack >>
end
; define-function
#+end_src
*** file-type-code->string
#+begin_src cicada-nymph :tangle core.cn
: file-type-code->string
<< file-type-code -- string[address, length] >>
dup 1 equal? << DT_FIFO >> if drop "named pipe i.e. FIFO" end then
dup 2 equal? << DT_CHR >> if drop "Character device" end then
dup 4 equal? << DT_DIR >> if drop "directory" end then
dup 6 equal? << DT_BLK >> if drop "block device" end then
dup 8 equal? << DT_REG >> if drop "regular file" end then
dup 10 equal? << DT_LNK >> if drop "symbolic link" end then
dup 12 equal? << DT_SOCK >> if drop "UNIX domain socket" end then
drop
"unknow file type"
end
; define-function
#+end_src
* port
*** 記 關於輸入輸出
* 接口設計分兩個層次
1. 底層的以 port 爲基礎的接口
這裏應該如何設計還不確定
可能會模仿操作系統所提供的接口
2. 高層的以 path 爲基礎的接口
這裏將抽象掉 port 這個概念
也就是每次簡單的讀寫都伴隨兩個對 port 的操作
這樣接口就很簡單 但是速度可能會非常慢
* 目前
二者的接口差異是通過前綴 port:體現出來的
*** note linux header
* 8 base number :
O_ACCMODE 0003
O_RDONLY 00
O_WRONLY 01
O_RDWR 02
O_CREAT 0100 Not fcntl
O_EXCL 0200 Not fcntl
O_NOCTTY 0400 Not fcntl
O_TRUNC 01000 Not fcntl
O_APPEND 02000
O_NONBLOCK 04000
O_NDELAY O_NONBLOCK
O_SYNC 04010000
O_FSYNC O_SYNC
O_ASYNC 020000
O_LARGEFILE 0100000
O_DIRECTORY 0200000
O_NOFOLLOW 0400000
O_CLOEXEC 02000000
O_DIRECT 040000
O_NOATIME 01000000
O_PATH 010000000
O_DSYNC 010000
O_TMPFILE 020200000
*** note interface
* open to read
* create and update to write
|--------+-----------------------|
| create | fail if already exist |
| update | fail if nor exist |
|--------+-----------------------|
* one should always know if a file exist or not
when open it as output-port
predicates are provided to help you to do so
*** note syscall with string arguments
* for syscall the arguments in stack look like
<< ..., arg3, arg2, arg1 >>
so
for read(port, buffer, size)
we need
<< size, buffer, port >>
but the interface (port:read) in cicada-nymph is
<< buffer, size, port >>
thus we need a swap here
and
we should be careful
for other interface functions in cicada-nymph
*** port:open
#+begin_src cicada-nymph :tangle core.cn
: port:open
<< path[address, length]
-- port, true
-- error-code, false >>
string->syscall-string
>:syscall-path
0 <<
O_RDONLY
>>
:syscall-path
syscall-number:*open*
2 syscall
dup
negative? if
false
end
then
true
end
; define-function
#+end_src
*** port:create
#+begin_src cicada-nymph :tangle core.cn
: port:create
<< path[address, length]
-- port, true
-- error-code, false >>
string->syscall-string
>:syscall-path
8#644 <<
2#110100100
>>
8#1102 <<
O_RDWR 0002
O_CREAT 0100
O_TRUNC 1000
>>
:syscall-path
syscall-number:*open*
3 syscall
dup
negative? if
false
end
then
true
end
; define-function
#+end_src
*** port:update
#+begin_src cicada-nymph :tangle core.cn
: port:update
<< path[address, length]
-- port, true
-- error-code, false >>
string->syscall-string
>:syscall-path
8#644 <<
110100100b
>>
8#1002 <<
O_RDWR 0002
O_TRUNC 1000
>>
:syscall-path
syscall-number:*open*
3 syscall
dup
negative? if
false
end
then
true
end
; define-function
#+end_src
*** port:close
#+begin_src cicada-nymph :tangle core.cn
: port:close
<< port
-- true
-- error-code, false >>
syscall-number:*close*
1 syscall
dup
negative? if
false
end
then
drop true
end
; define-function
#+end_src
*** port:read
#+begin_src cicada-nymph :tangle core.cn
: port:read
<< buffer, max-size, port
-- counter, true
-- error-code, false >>
>:port
swap
:port
syscall-number:*read*
3 syscall
dup
negative? if
false
end
then
true
end
; define-function
#+end_src
*** port:write
#+begin_src cicada-nymph :tangle core.cn
: port:write
<< buffer, max-size, port
-- counter, true
-- error-code, false >>
>:port
swap
:port
syscall-number:*write*
3 syscall
dup
negative? if
false
end
then
true
end
; define-function
#+end_src
*** test
#+begin_src cicada-nymph
: k
<< -- >>
"kkk~" port:create if
port:close if
end
then error-code->string .s .l end
then error-code->string .s .l end
; define-function
k
: k
<< -- >>
"kkk~" port:update if
port:close if
end
then error-code->string .s .l end
then error-code->string .s .l end
; define-function
k
: k
<< -- >>
64 allocate-local-memory
dup
"kkk~" port:open if
64 swap port:read if
.s .l
end
then error-code->string .s .l end
then error-code->string .s .l end
; define-function
k
#+end_src
* file
*** note interface
* note that
the concept of port is
completely removed from the interface
* file-tree
two types of nodes
1. file
2. directory
a leaf must be a file
* the interface
1. use path as an argument
2. print error message on error
instead of
return error info
or do non-local-exit
*** 記 元數據
* 訪問管理
1. 誰有權訪問這個文件
2. 他的權利是什麼
* 文件類型
[linux 沒有]
* 文件大小
* 文件使用註釋
[linux 沒有]
*** file:create
#+begin_src cicada-nymph :tangle core.cn
: file:create
<< path[address, length] -- >>
>::path
::path
string->syscall-string
>:syscall-path
8#644 <<
2#110100100
>>
8#0200
8#0100 bit-or <<
O_EXCL 0200
O_CREAT 0100
>>
:syscall-path
syscall-number:*open*
3 syscall
dup
negative? if
"* (file:create) fail to open port for the following path :" .s .l
" " .s ::path .s .l
" " .s error-code->string .s .l
end
then
port:close if
end
then
"* (file:create) fail to close port for the following path :" .s .l
" " .s ::path .s .l
" " .s error-code->string .s .l
end
; define-function
#+end_src
*** file:write
#+begin_src cicada-nymph :tangle core.cn
: file:write
<< string[address, length], path[address, length] -- >>
>::path
>::string
::path
string->syscall-string
>:syscall-path
8#644 <<
2#110100100
>>
8#1002 <<
O_RDWR 0002
O_TRUNC 1000
>>
:syscall-path
syscall-number:*open*
3 syscall
dup
negative? if
"* (file:write) fail to open port for the following path :" .s .l
" " .s ::path .s .l
" " .s error-code->string .s .l
end
then
>:port
::string swap
:port
syscall-number:*write*
3 syscall
dup
negative? if
"* (file:write) fail to write port for the following path :" .s .l
" " .s ::path .s .l
" " .s error-code->string .s .l
end
then
>:counter << bytes been written >>
:port
port:close if
end
then
"* (file:write) fail to close port for the following path : " .s .l
" " .s ::path .s .l
" " .s error-code->string .s .l
end
; define-function
#+end_src
*** file:read
#+begin_src cicada-nymph :tangle core.cn
: file:read
<< string[address, max-length], path[address, length] -- counter >>
>::path
>::string
::path
string->syscall-string
>:syscall-path
0 <<
O_RDONLY
>>
:syscall-path
syscall-number:*open*
2 syscall
dup
negative? if
"* (file:read) fail to open port for the following path :" .s .l
" " .s ::path .s .l
" " .s error-code->string .s .l
0
end
then
>:port
::string swap
:port
syscall-number:*read*
3 syscall
dup
negative? if
"* (file:read) fail to read port for the following path :" .s .l
" " .s ::path .s .l
" " .s error-code->string .s .l
0
end
then
>:counter << bytes been readed >>
:port
port:close if
:counter
end
then
"* (file:read) fail to close port for the following path : " .s .l
" " .s ::path .s .l
" " .s error-code->string .s .l
0
end
; define-function
#+end_src
*** file:remove
#+begin_src cicada-nymph :tangle core.cn
: file:remove
<< path[address, length] -- >>
>::path
::path
string->syscall-string
>:syscall-path
:syscall-path
syscall-number:*unlink*
1 syscall
dup
negative? if
"* (file:remove) fail for the following path :" .s .l
" " .s ::path .s .l
" " .s error-code->string .s .l
end
then
drop
end
; define-function
#+end_src
*** test file
#+begin_src cicada-nymph :tangle core-test.cn
: file,test
<< -- >>
"kkk~" file:create
"kkk took my baby away" dup >:length
"kkk~" file:write
"............................" >::string
::string "kkk~" file:read >:counter
:counter
:length
equal? test
"kkk took my baby away......."
::string
string:equal? test
"kkk~" file:remove
end
; test-function
: "* (testing) file" .s .l
file,test
; test-do
#+end_src
* directory
*** directory:create
#+begin_src cicada-nymph :tangle core.cn
: directory:create
<< path[address, length] -- >>
>::path
::path
string->syscall-string
>:syscall-path
8#755 <<
2#111101101
>>
:syscall-path
syscall-number:*mkdir*
2 syscall
dup
negative? if
"* (directory:create) fail for the following path :" .s .l
" " .s ::path .s .l
" " .s error-code->string .s .l
end
then
drop
end
; define-function
#+end_src
*** directory:remove
#+begin_src cicada-nymph :tangle core.cn
: directory:remove
<< path[address, length] -- >>
>::path
::path
string->syscall-string
>:syscall-path
:syscall-path
syscall-number:*rmdir*
1 syscall
dup
negative? if
"* (directory:remove) fail for the following path :" .s .l
" " .s ::path .s .l
" " .s error-code->string .s .l
end
then
drop
end
; define-function
#+end_src
*** test
#+begin_src cicada-nymph
"kkk" directory:create
"kkk" directory:remove
#+end_src
*** system-getdents64
#+begin_src cicada-nymph :tangle core.cn
0 : +getdents64,ino+ ; define-variable,with-tos
0 : +getdents64,off+ ; define-variable,with-tos
0 : +getdents64,reclen+ ; define-variable,with-tos
0 : +getdents64,type+ ; define-variable,with-tos
0 : +getdents64,name+ ; define-variable,with-tos
0 : +getdents64,end+ ; define-variable,with-tos
: init,getdents64
<< offset -- >>
*cell-size* 4 equal? if
dup address +getdents64,ino+ set 8 add
dup address +getdents64,off+ set 8 add
dup address +getdents64,reclen+ set 2 add
dup address +getdents64,type+ set 1 add
dup address +getdents64,name+ set 256 add
address +getdents64,end+ set
end
then
*cell-size* 8 equal? if
dup address +getdents64,ino+ set 8 add
dup address +getdents64,off+ set 8 add
dup address +getdents64,reclen+ set 2 add
dup address +getdents64,type+ set 1 add
dup address +getdents64,name+ set 256 add
address +getdents64,end+ set
end
then
end
; define-function
0 init,getdents64
+getdents64,end+ : +getdents64,length+ ; define-variable,with-tos
#+end_src
*** test
#+begin_src cicada-nymph
: test,getdents64,print
<< -- >>
"+getdents64,ino+ : " .s +getdents64,ino+ get . .l
"+getdents64,off+ : " .s +getdents64,off+ get . .l
"+getdents64,reclen+ : " .s +getdents64,reclen+ get-two-bytes . .l
"+getdents64,type+ : " .s
+getdents64,type+
get-byte file-type-code->string .s .l
"+getdents64,name+ : " .s
+getdents64,name+
dup 256
0 string:find-byte
drop << drop 0 >>
over sub .s .l
.l
end
; define-function
: test,getdents64,loop,structure
<< end, cursor -- >>
dup2 less-or-equal? if
drop2
end
then
>:cursor
:cursor init,getdents64
test,getdents64,print
:cursor +getdents64,reclen+ get-two-bytes add
loop
; define-function
: test,getdents64,loop
<< port -- >>
>:port
1024 allocate-local-memory >:getdents64-structure-list
1024
:getdents64-structure-list
:port
syscall-number:*getdents64*
3 syscall
"* syscall returns : " .s dup .i .l
dup negative? if
error-code->string .s .l
end
then
dup zero? if
drop
end
then
:getdents64-structure-list add
:getdents64-structure-list
test,getdents64,loop,structure
:port
loop
; define-function
: test,getdents64
<< path[address, length] -- >>
>::path
::path port:open if
else
"* (test,getdents64) fail to open : " .s ::path .s .l
" " .s error-code->string .s .l
end
then
>:port
:port test,getdents64,loop
:port port:close if
end
then
"* (test,getdents64) fail to close : " .s ::path .s .l
" " .s error-code->string .s .l
end
; define-function
"play" test,getdents64
"play/kkk" test,getdents64
"." test,getdents64
"/" test,getdents64
#+end_src
*** directory:empty?
#+begin_src cicada-nymph :tangle core.cn
: directory:empty?
<< path[address, length] -- bool >>
>::path
::path port:open if
else
"* (directory:empty?) fail to open : " .s ::path .s .l
" " .s error-code->string .s .l
false
end
then
>:port
128 allocate-local-memory >:getdents64-structure-list
128
:getdents64-structure-list
:port
syscall-number:*getdents64*
3 syscall
48 equal? << this call to equal? returns the needed bool >>
:port port:close if
end
then
"* (directory:empty?) fail to close : " .s ::path .s .l
" " .s error-code->string .s .l
false
end
; define-function
#+end_src
*** test
#+begin_src cicada-nymph
"play" directory:empty? . .l
"play/kkk" directory:empty? . .l
"play/aaa" directory:empty? . .l
"." directory:empty? . .l
"/" directory:empty? . .l
#+end_src
*** directory:map
#+begin_src cicada-nymph :tangle core.cn
: directory:map,loop,apply
<< end, cursor, function -- >>
>:function
dup2 less-or-equal? if
drop2
end
then
>:cursor
>:end
:cursor init,getdents64
:function apply
:end
:cursor +getdents64,reclen+ get-two-bytes add
:function
loop
; define-function
: directory:map,loop
<< port, function -- >>
>:function
>:port
1024 allocate-local-memory >:getdents64-structure-list
1024
:getdents64-structure-list
:port
syscall-number:*getdents64*
3 syscall
dup negative? if
"* (directory:map,loop) syscall fail" .s .l
" " .s error-code->string .s .l
end
then
dup zero? if
drop
end
then
:getdents64-structure-list add
:getdents64-structure-list
:function
directory:map,loop,apply
:port
:function
loop
; define-function
: directory:map
<< directory-path[address, length],
function
-- true
-- false >>
>:function
>::directory-path
::directory-path port:open if
else
"* (directory:map) fail to open : " .s ::directory-path .s .l
" " .s error-code->string .s .l
end
then
>:port
:port :function directory:map,loop
:port port:close if
end
then
"* (directory:map) fail to close : " .s ::directory-path .s .l
" " .s error-code->string .s .l
end
; define-function
#+end_src
*** test
#+begin_src cicada-nymph
: test,function
<< -- >>
+getdents64,type+ get-byte
8 equal? if
" " .s
+getdents64,name+
dup 256
0 string:find-byte
drop << drop 0 >>
over sub .s .l
then
end
; define-function
"play" jo test,function directory:map
#+end_src
*** directory:list-file
#+begin_src cicada-nymph :tangle core.cn
: directory:list-file
<< directory-path[address, length] -- >>
[ << -- >>
+getdents64,type+ get-byte
8 equal? if
" " .s
+getdents64,name+
dup 256
0 string:find-byte
drop << drop 0 >>
over sub .s .l
then
end ]
directory:map
end
; define-function
#+end_src
*** directory:list-directory
#+begin_src cicada-nymph :tangle core.cn
: directory:list-directory
<< directory-path[address, length] -- >>
[ << -- >>
+getdents64,type+ get-byte
4 equal? if
+getdents64,name+
dup 256
0 string:find-byte
drop << drop 0 >>
over sub >::name
".." ::name string:equal? if
end
then
"." ::name string:equal? if
end
then
" " .s ::name .s .l
end
then
end ]
directory:map
end
; define-function
#+end_src
*** test
#+begin_src cicada-nymph
"play" dup2
directory:list-file
directory:list-directory
"play/kkk" dup2
directory:list-file
directory:list-directory
"." dup2
directory:list-file
directory:list-directory
"/" dup2
directory:list-file
directory:list-directory
#+end_src
*** directory:find-file
#+begin_src cicada-nymph :tangle core.cn
: directory:find-file
<< directory-path[address, length], file-name[address, length] -- bool >>
xx|swap|xx
false
xx|swap|x
[ << file-name[address, length], bool --
file-name[address, length], bool >>
+getdents64,type+ get-byte 8 equal? not if
end
then
>:bool
>:file-name,lenght
>:file-name,address
:file-name,lenght +getdents64,name+ add
get-byte zero? not if
:file-name,address
:file-name,lenght
:bool
end
then
:file-name,address :file-name,lenght
+getdents64,name+ :file-name,lenght
string:equal? if
:file-name,address
:file-name,lenght
true
end
then
:file-name,address
:file-name,lenght
:bool
end ]
directory:map
xx|swap|x drop2
end
; define-function
#+end_src
*** directory:find-directory
#+begin_src cicada-nymph :tangle core.cn
: directory:find-directory
<< directory-path[address, length], file-name[address, length] -- bool >>
xx|swap|xx
false
xx|swap|x
[ << file-name[address, length], bool --
file-name[address, length], bool >>
+getdents64,type+ get-byte 4 equal? not if
end
then
>:bool
>:file-name,lenght
>:file-name,address
:file-name,lenght +getdents64,name+ add
get-byte zero? not if
:file-name,address
:file-name,lenght
:bool
end
then
:file-name,address :file-name,lenght
+getdents64,name+ :file-name,lenght
string:equal? if
:file-name,address
:file-name,lenght
true
end
then
:file-name,address
:file-name,lenght
:bool
end ]
directory:map
xx|swap|x drop2
end
; define-function
#+end_src
*** test
#+begin_src cicada-nymph
: find-file,test
<< -- >>
"play" "cn" directory:find-file .
"play" "kkk" directory:find-file .
"play" "no" directory:find-file .
.l
"playlay" "no" directory:find-file .
.l
end
; define-function
find-file,test
: find-directory,test
<< -- >>
"play" "cn" directory:find-directory .
"play" "kkk" directory:find-directory .
"play" "no" directory:find-directory .
.l
"playlay" "no" directory:find-directory .
.l
end
; define-function
find-directory,test
#+end_src
* system environment
*** note linux
***** one directory
* all files about cicada
are stored in
"/home//.cicada"
***** pid
* pid is the key to all the linux system environment
* command-line
/proc//cmdline
* environment-variable-list
/proc//environ
*** [init|get]-pid
#+begin_src cicada-nymph :tangle core.cn
0 : *pid* ; define-variable,with-tos
: init-pid
<< -- >>
syscall-number:*getpid*
0 syscall
address *pid* set
end
; define-function
: get-pid
<< -- pid >>
*pid*
end
; define-function
#+end_src
*** [init|get]-command-line
#+begin_src cicada-nymph :tangle core.cn
512 allocate-memory
: *address,command-line*
; define-variable,with-tos
512
: *length,command-line*
; define-variable,with-tos
: init-command-line
<< -- >>
64 allocate-local-memory >:path-buffer
:path-buffer >:cursor
get-pid write-number,fill-buffer >::pid-string
"/proc/" dup >:add-to-cursor
:cursor string->buffer!
:add-to-cursor :cursor add >:cursor
::pid-string dup >:add-to-cursor
:cursor string->buffer!
:add-to-cursor :cursor add >:cursor
"/cmdline" dup >:add-to-cursor
:cursor string->buffer!
:add-to-cursor :cursor add >:cursor
:path-buffer
:cursor :path-buffer sub dup2 >::path
port:open if
else
"* (init-command-line) fail to open : " .s ::path .s .l
end
then
>:port
*address,command-line*
*length,command-line*
:port
port:read if
else
"* (init-command-line) fail to read : " .s ::path .s .l
end
then
address *length,command-line* set
end
; define-function
: get-command-line
<< -- string[address, length] >>
*address,command-line* *length,command-line*
end
; define-function
#+end_src
*** [init|get]-environment-variable-list
* the size of /proc//environ is limited to 4k
#+begin_src cicada-nymph :tangle core.cn
1024 4 mul allocate-memory
: *address,environment-variable-list*
; define-variable,with-tos
1024 4 mul
: *length,environment-variable-list*
; define-variable,with-tos
: init-environment-variable-list
<< -- >>
64 allocate-local-memory >:path-buffer
:path-buffer >:cursor
get-pid write-number,fill-buffer >::pid-string
"/proc/" dup >:add-to-cursor
:cursor string->buffer!
:add-to-cursor :cursor add >:cursor
::pid-string dup >:add-to-cursor
:cursor string->buffer!
:add-to-cursor :cursor add >:cursor
"/environ" dup >:add-to-cursor
:cursor string->buffer!
:add-to-cursor :cursor add >:cursor
:path-buffer
:cursor :path-buffer sub dup2 >::path
port:open if
else
"* (init-environment-variable-list) fail to open : " .s ::path .s .l
end
then
>:port
*address,environment-variable-list*
*length,environment-variable-list*
:port
port:read if
else
"* (init-environment-variable-list) fail to read : " .s ::path .s .l
end
then
address *length,environment-variable-list* set
end
; define-function
: get-environment-variable-list
<< -- string[address, length] >>
*address,environment-variable-list*
*length,environment-variable-list*
end
; define-function
#+end_src
*** find-environment-variable
* the string used to find an environment-variable
can not contain "="
no error handling on this
#+begin_src cicada-nymph :tangle core.cn
: find-environment-variable,loop
<< string[address, length], cursor
-- string[address, length], true
-- false >>
dup
get-environment-variable-list add
greater-than? if
drop drop2
false
end
then
>:cursor
>:length
>:address
:address :cursor :length
compare-buffer not if
:address :length
:cursor 0 cursor->next-matching-byte add1
loop
then
:cursor :length add get-byte
"=" string:byte
equal? not if
:address :length
:cursor 0 cursor->next-matching-byte add1
loop
then
:cursor :length add add1 << over "=" >>
>:find-address
:find-address 0 cursor->next-matching-byte
:find-address sub >:find-length
:find-address
:find-length
end
; define-function
: find-environment-variable
<< string[address, length]
-- string[address, length], true
-- false >>
get-environment-variable-list drop
find-environment-variable,loop
end
; define-function
#+end_src
*** initialize system environment
#+begin_src cicada-nymph :tangle core.cn
init-pid
init-command-line
init-environment-variable-list
#+end_src
*** *home-directory*
#+begin_src cicada-nymph :tangle core.cn
: *home-directory*
"HOME" find-environment-variable
; define-variable
#+end_src
*** report:environment-variable
#+begin_src cicada-nymph :tangle core.cn
: report:environment-variable,loop
<< environment-variable-list[address, length]-- >>
dup2 string:space? if
drop2
end
then
>:length
>:address
:address :length 0 string:find-byte drop add1 >:cursor
:cursor :address sub >:length-of-one-variable
:address
:length-of-one-variable sub1 .s .l
:cursor
:length :length-of-one-variable sub
loop
; define-function
: report:environment-variable
<< -- >>
get-environment-variable-list
report:environment-variable,loop
end
; define-function
#+end_src
*** report:command-line
#+begin_src cicada-nymph :tangle core.cn
: report:command-line,loop
<< command-line[address, length] -- >>
dup2 string:space? if
drop2
end
then
dup2 string:word .s 32 .b
string:word-tail
loop
; define-function
: report:command-line
<< -- >>
get-command-line
report:command-line,loop
end
; define-function
#+end_src
* work-directory
*** work-directory:get
#+begin_src cicada-nymph :tangle core.cn
512 allocate-memory
: *buffer,work-directory*
; define-variable,with-tos
: work-directory:get
<< -- directory[address, length] >>
512
*buffer,work-directory*
syscall-number:*getcwd*
2 syscall
dup negative? if
"* (work-directory:get) fail" .s .l
" " .s error-code->string .s .l
end
then
*buffer,work-directory*
swap
sub1 << for the ending zero >>
end
; define-function
#+end_src
*** work-directory:change
#+begin_src cicada-nymph :tangle core.cn
: work-directory:change
<< directory-path[address, length] -- >>
>::directory-path
::directory-path
string->syscall-string
syscall-number:*chdir*
1 syscall
dup negative? if
"* (work-directory:change) fail" .s .l
" can not change the work directory into : " .s ::directory-path .s .l
" thus the argument in the stack is not consumed" .s .l
" " .s error-code->string .s .l
::directory-path
end
then
drop
end
; define-function
#+end_src
*** pwd
* print work-directory
#+begin_src cicada-nymph :tangle core.cn
: pwd
<< -- >>
work-directory:get .s .l
end
; define-function
#+end_src
*** cd
* change work-directory
#+begin_src cicada-nymph :tangle core.cn
"cd" "work-directory:change" alias
#+end_src
*** test
#+begin_src cicada-nymph
pwd
"/home" cd
pwd
"/////home/xyh////cicada/play" cd
pwd
"//././/home/xyh/././cicada/./" cd
pwd
#+end_src
* path
*** system-stat
#+begin_src cicada-nymph :tangle core.cn
0 : +stat,dev+ ; define-variable,with-tos
0 : +stat,ino+ ; define-variable,with-tos
0 : +stat,mode+ ; define-variable,with-tos
0 : +stat,nlink+ ; define-variable,with-tos
0 : +stat,uid+ ; define-variable,with-tos
0 : +stat,gid+ ; define-variable,with-tos
0 : +stat,rdev+ ; define-variable,with-tos
0 : +stat,size+ ; define-variable,with-tos
0 : +stat,blksize+ ; define-variable,with-tos
0 : +stat,blocks+ ; define-variable,with-tos
0 : +stat,atime+ ; define-variable,with-tos
0 : +stat,atime_nsec+ ; define-variable,with-tos
0 : +stat,mtime+ ; define-variable,with-tos
0 : +stat,mtime_nsec+ ; define-variable,with-tos
0 : +stat,ctime+ ; define-variable,with-tos
0 : +stat,ctime_nsec+ ; define-variable,with-tos
0 : +stat,__unused4+ ; define-variable,with-tos
0 : +stat,__unused5+ ; define-variable,with-tos
0 : +stat,end+ ; define-variable,with-tos
: init,stat
<< offset -- >>
*cell-size* 4 equal? if
dup address +stat,dev+ set *cell-size* add
dup address +stat,ino+ set *cell-size* add
dup address +stat,mode+ set 2 add
dup address +stat,nlink+ set 2 add
dup address +stat,uid+ set 2 add
dup address +stat,gid+ set 2 add
dup address +stat,rdev+ set *cell-size* add
dup address +stat,size+ set *cell-size* add
dup address +stat,blksize+ set *cell-size* add
dup address +stat,blocks+ set *cell-size* add
dup address +stat,atime+ set *cell-size* add
dup address +stat,atime_nsec+ set *cell-size* add
dup address +stat,mtime+ set *cell-size* add
dup address +stat,mtime_nsec+ set *cell-size* add
dup address +stat,ctime+ set *cell-size* add
dup address +stat,ctime_nsec+ set *cell-size* add
dup address +stat,__unused4+ set *cell-size* add
dup address +stat,__unused5+ set *cell-size* add
address +stat,end+ set
end
then
*cell-size* 8 equal? if
dup address +stat,dev+ set *cell-size* add
dup address +stat,ino+ set *cell-size* add
<<
note the following order changing
this is linux' bad
>>
dup address +stat,nlink+ set 8 add
dup address +stat,mode+ set 4 add
dup address +stat,uid+ set 4 add
dup address +stat,gid+ set 4 add
4 add << padding >>
dup address +stat,rdev+ set *cell-size* add
dup address +stat,size+ set *cell-size* add
dup address +stat,blksize+ set *cell-size* add
dup address +stat,blocks+ set *cell-size* add
dup address +stat,atime+ set *cell-size* add
dup address +stat,atime_nsec+ set *cell-size* add
dup address +stat,mtime+ set *cell-size* add
dup address +stat,mtime_nsec+ set *cell-size* add
dup address +stat,ctime+ set *cell-size* add
dup address +stat,ctime_nsec+ set *cell-size* add
dup address +stat,__unused4+ set *cell-size* add
dup address +stat,__unused5+ set *cell-size* add
address +stat,end+ set
end
then
end
; define-function
0 init,stat
+stat,end+ : +stat,length+ ; define-variable,with-tos
#+end_src
*** test
#+begin_src cicada-nymph
: test,stat
<< path[address, length] -- >>
string->syscall-string
>:syscall-path
+stat,length+ allocate-local-memory
>:stat-structure
:stat-structure
:syscall-path
syscall-number:*stat*
2 syscall
dup
negative? if
dup .
error-code->string .s .l
end
then
drop
:stat-structure init,stat
"+stat,dev+ : " .s +stat,dev+ get . .l
"+stat,ino+ : " .s +stat,ino+ get . .l
*cell-size* 4 equal? if
"+stat,mode+ : " .s +stat,mode+ get-two-bytes . .l
"+stat,nlink+ : " .s +stat,nlink+ get-two-bytes . .l
"+stat,uid+ : " .s +stat,uid+ get-two-bytes . .l
"+stat,gid+ : " .s +stat,gid+ get-two-bytes . .l
then
*cell-size* 8 equal? if
"+stat,nlink+ : " .s +stat,nlink+ get . .l
"+stat,mode+ : " .s +stat,mode+ get-four-bytes . .l
"+stat,uid+ : " .s +stat,uid+ get-four-bytes . .l
"+stat,gid+ : " .s +stat,gid+ get-four-bytes . .l
then
"+stat,rdev+ : " .s +stat,rdev+ get . .l
"+stat,size+ : " .s +stat,size+ get . .l
"+stat,blksize+ : " .s +stat,blksize+ get . .l
"+stat,blocks+ : " .s +stat,blocks+ get . .l
"+stat,atime+ : " .s +stat,atime+ get . .l
"+stat,atime_nsec+ : " .s +stat,atime_nsec+ get . .l
"+stat,mtime+ : " .s +stat,mtime+ get . .l
"+stat,mtime_nsec+ : " .s +stat,mtime_nsec+ get . .l
"+stat,ctime+ : " .s +stat,ctime+ get . .l
"+stat,ctime_nsec+ : " .s +stat,ctime_nsec+ get . .l
"+stat,__unused4+ : " .s +stat,__unused4+ get . .l
"+stat,__unused5+ : " .s +stat,__unused5+ get . .l
end
; define-function
"cn" test,stat
"no" test,stat
#+end_src
*** note predicate
* to use predicate to know more about the file-tree
before calling a function that makes action on the file-tree
*** path:nothing?
#+begin_src cicada-nymph :tangle core.cn
: path:nothing?
<< path[address, length] -- bool >>
string->syscall-string
>:syscall-path
+stat,length+ allocate-local-memory
>:stat-structure
:stat-structure
:syscall-path
syscall-number:*stat*
2 syscall
-2 equal?
end
; define-function
#+end_src
*** path:file?
#+begin_src cicada-nymph :tangle core.cn
: path:file?
<< path[address, length] -- bool >>
string->syscall-string
>:syscall-path
+stat,length+ allocate-local-memory
>:stat-structure
:stat-structure
:syscall-path
syscall-number:*stat*
2 syscall
dup
negative? if
drop
false
end
then
drop
:stat-structure init,stat
*cell-size* 4 equal? if
+stat,mode+
get-two-bytes
then
*cell-size* 8 equal? if
+stat,mode+
get-four-bytes
then
12 bit-right
8#0010
equal?
<<
0170000
S_IFDIR 0040000 /* Directory. */
S_IFCHR 0020000 /* Character device. */
S_IFBLK 0060000 /* Block device. */
S_IFREG 0100000 /* Regular file. */
S_IFIFO 0010000 /* FIFO. */
S_IFLNK 0120000 /* Symbolic link. */
S_IFSOCK 0140000 /* Socket. */
>>
end
; define-function
#+end_src
*** path:directory?
#+begin_src cicada-nymph :tangle core.cn
: path:directory?
<< path[address, length] -- bool >>
string->syscall-string
>:syscall-path
+stat,length+ allocate-local-memory
>:stat-structure
:stat-structure
:syscall-path
syscall-number:*stat*
2 syscall
dup
negative? if
drop
false
end
then
drop
:stat-structure init,stat
*cell-size* 4 equal? if
+stat,mode+
get-two-bytes
then
*cell-size* 8 equal? if
+stat,mode+
get-four-bytes
then
12 bit-right
8#0004
equal?
<<
0170000
S_IFDIR 00040000 /* Directory. */
S_IFCHR 00020000 /* Character device. */
S_IFBLK 00060000 /* Block device. */
S_IFREG 00100000 /* Regular file. */
S_IFIFO 00010000 /* FIFO. */
S_IFLNK 00120000 /* Symbolic link. */
S_IFSOCK 00140000 /* Socket. */
>>
end
; define-function
#+end_src
*** test
#+begin_src cicada-nymph
"cn" path:nothing? . << 0 >>
"core" path:nothing? . << 0 >>
"ai" path:nothing? . << 1 >>
"cn" path:file? . << 1 >>
"core" path:file? . << 0 >>
"ai" path:file? . << 0 >>
"cn" path:directory? . << 0 >>
"core" path:directory? . << 1 >>
"ai" path:directory? . << 0 >>
#+end_src
*** 記 字符串的謂詞
* 下面這兩個函數
其實是在用遞歸函數實現正則表達式對字符串的匹配效果
* 是否應該設計 正則表達式 子語言 ?
還是總是直接使用遞歸函數 ?
*** 記 unix 路徑格式
* "/" 相當於 空格
連續的 "//" 相當於 連續的空格
這種空格使用在字符串開頭時 代表這是一個 絕對路徑
* "." 相當於 空格
連續的 ".." 不算 連續的空格 有別的語義
但是在這種空格使用在最前面的時候 標誌這個
這種空格使用在字符串開頭時 代表這是一個 相對路徑
* 而對於下面的兩個函數我簡單地要求
1. relative-path
不以 "/" 開頭 的字符串
2. full-path
以 "/" 開頭 的字符串
3. 並且在這裏我允許 path 內 出現空格
保留對這種路徑的處理能力
只不過 我不使用這種路徑而已
*** path:relative?
* in ASCII "/" is 47
#+begin_src cicada-nymph :tangle core.cn
: path:relative?
<< string[address, length] -- bool >>
dup zero? if
drop2
false
end
then
string:byte
47 equal? not
end
; define-function
#+end_src
*** path:full?
* in ASCII "/" is 47
#+begin_src cicada-nymph :tangle core.cn
: path:full?
<< string[address, length] -- bool >>
dup zero? if
drop2
false
end
then
string:byte
47 equal?
end
; define-function
#+end_src
*** test path:full?
#+begin_src cicada-nymph :tangle core-test.cn
: "* (testing) path:full?" .s .l
"/home" path:relative? false?
"/home" path:full? true? and
"home" path:relative? true? and
"home" path:full? false? and test
; test-do
#+end_src
* poi
*** 記
* poi 是利用文件系統所實現的登記機制
所登記的 path 信息爲 path-syntax 所用
* module 也是用文件系統所實現的登記機制
所登記的 path 信息爲 module 機制所用
*** note
* poi denotes path-organizer
it can give a name to a path
one path one name
* a path as a string must not contain any space bytes
* a name should only consist of number or letter or "-"
*** *poi-directory*
* one directory to store the name path record
"/home//.cicada/poi"
#+begin_src cicada-nymph :tangle core.cn
: *poi-directory,user,address*
512 allocate-memory
; define-variable
: *poi-directory*
*home-directory* "/.cicada/poi"
*poi-directory,user,address*
2 n-string->buffer!
*poi-directory,user,address* swap
; define-variable
#+end_src
*** poi:find
* note that
this function uses *circular-string-area*
#+begin_src cicada-nymph :tangle core.cn
: poi:find
<< name[address, length]
-- path[address, length], true
-- false >>
>::name
512 allocate-local-memory >:buffer
*poi-directory* "/" ::name "/path"
:buffer
4 n-string->buffer! >:length
:buffer :length
path:file? not if
false
end
then
512 allocate-local-memory >:read-buffer
:read-buffer 512
:buffer :length
file:read >:read-length
*circular-string-area,current-free-address*
>:path-address
:read-buffer :read-length
circular-string-area,stay
:path-address
:read-length
true
end
; define-function
#+end_src
*** poi:add
#+begin_src cicada-nymph :tangle core.cn
: poi:add
<< name[address, length], relative-path[address, length] -- >>
>::relative-path
>::name
::relative-path path:relative? not if
"* (poi:add) the argument must be a relative-path" .s .l
" but the following is not : " .s ::relative-path .s .l
end
then
::relative-path path:directory? not if
"* (poi:add) the argument must be a relative-path to a existing directory" .s .l
" but the following path is not to a directory : " .s ::relative-path .s .l
end
then
::name poi:find if
"* (poi:add) can not add" .s .l
" for the following poi already exist : " .s ::name .s .l
" name is use as the following directory's name : " .s .s .l
end
then
512 allocate-local-memory >:buffer
*poi-directory* "/" ::name
:buffer
3 n-string->buffer!
>:length
:buffer :length
directory:create
*poi-directory* "/" ::name "/path"
:buffer
4 n-string->buffer!
>:length
:buffer :length
file:create
512 allocate-local-memory >:address,full-path
work-directory:get "/" ::relative-path
:address,full-path
3 n-string->buffer! >:length,full-path
:address,full-path :length,full-path
:buffer :length
file:write
end
; define-function
#+end_src
*** poi:sub
#+begin_src cicada-nymph :tangle core.cn
: poi:sub
<< name[address, length] -- >>
>::name
::name poi:find not if
"* (poi:sub) can not sub" .s .l
" for the following poi does not exist : " .s ::name .s .l
end
then
>::named-directory
512 allocate-local-memory >:buffer
*poi-directory* "/" ::name "/path"
:buffer
4 n-string->buffer! >:length
:buffer :length
file:remove
*poi-directory* "/" ::name
:buffer
3 n-string->buffer!
>:length
:buffer :length
directory:remove
end
; define-function
#+end_src
*** poi:up
#+begin_src cicada-nymph :tangle core.cn
: poi:up
<< name[address, length], relative-path[address, length] -- >>
>::relative-path
>::name
::relative-path path:relative? not if
"* (poi:up) the argument must be a relative-path" .s .l
" but the following is not : " .s ::relative-path .s .l
end
then
::relative-path path:directory? not if
"* (poi:up) the argument must be a relative-path to a existing directory" .s .l
" but the following directory is not exist : " .s ::relative-path .s .l
end
then
::name poi:find not if
"* (poi:up) can not up" .s .l
" for the following poi does not exist : " .s ::name .s .l
end
then
>::named-directory
512 allocate-local-memory >:buffer
*poi-directory* "/" ::name "/path"
:buffer
4 n-string->buffer! >:length
512 allocate-local-memory >:address,full-path
work-directory:get "/" ::relative-path
:address,full-path
3 n-string->buffer! >:length,full-path
:address,full-path :length,full-path
:buffer :length
file:write
end
; define-function
#+end_src
*** poi:list
#+begin_src cicada-nymph :tangle core.cn
: poi:list
<< -- >>
*poi-directory*
[ << -- >>
+getdents64,type+ get-byte
4 equal? if
512 allocate-local-memory >:path-buffer
+getdents64,name+
dup 256
0 string:find-byte
drop << drop 0 >>
over sub >::name
".." ::name string:equal? if
end
then
"." ::name string:equal? if
end
then
" * " .s ::name .s .l
" " .s
*poi-directory* "/" ::name "/path"
:path-buffer
4 n-string->buffer! >:path-length
512 allocate-local-memory >:reading-buffer
:reading-buffer 512
:path-buffer :path-length
file:read >:reading-length
:reading-buffer :reading-length
.s .l
then
end ]
directory:map
end
; define-function
#+end_src
*** poi:help
#+begin_src cicada-nymph :tangle core.cn
: poi:help
<< -- >>
"* (poi:help)" .s .l
" * cn poi add " .s .l
" * cn poi sub " .s .l
" * cn poi up " .s .l
" * cn poi find " .s .l
" * cn poi list" .s .l
end
; define-function
#+end_src
*** test
#+begin_src cicada-nymph
"test-cicada-play" "./play" poi:add
"test-cicada-play" poi:find
if .s .l
else "not found" .s .l
then
"test-cicada-play-2" "./play-2" poi:add
"test-cicada-play-2" poi:find
if .s .l
else "not found" .s .l
then
"test-cicada-play" "./contribution" poi:up
"test-cicada-play" poi:find
if .s .l
else "not found" .s .l
then
"test-cicada-play" poi:sub
"test-cicada-play" poi:find
if .s .l
else "not found" .s .l
then
poi:list
poi:help
#+end_src
* word-interpreter-syntax:path
*** +word+?
#+begin_src cicada-nymph :tangle core.cn
: +word+?
<< string[address, length] -- bool >>
dup 1 less-or-equal? if
drop2
false
end
then
over get-byte
"+" string:byte equal? not if
drop2
false
end
then
add sub1 get-byte
"+" string:byte equal?
end
; define-function
#+end_src
*** +word+->word
#+begin_src cicada-nymph :tangle core.cn
: +word+->word
<< +word+[address, length] -- name[address, length] >>
sub2 swap
add1 swap
end
; define-function
#+end_src
*** test
#+begin_src cicada-nymph
"+work+" +word+? .
"work" +word+? .
#+end_src
*** note
* path syntax can be implemented by a new *syntax-rule-set*
but in the following
I just simply implemented it
as a syntax-rule in syntax-rule-set:*word-interpreter*
*** note format
#+begin_src cicada-nymph
<<
the following 4 poi are built in
+root+
+home+
+work+
+back+
>>
path: +root+ home xyh cicada core core.cn ;
path: +home+ cicada core core.cn ;
"/home/xyh/cicada/core/core.cn"
path: +back+ cicada core core.cn ;
"../cicada/core/core.cn"
path: +work+ core core.cn ;
path: core core.cn ;
path: +library+ hi.cn ;
"/home/xyh/cicada/library/hi.cn"
#+end_src
*** path-syntax-word->path
#+begin_src cicada-nymph :tangle core.cn
: path-syntax-word->path
<< word[address, length] -- path[address, length] >>
>::word
::word "+root+" string:equal? if
"/"
end
then
::word "+work+" string:equal? if
work-directory:get
end
then
::word "+home+" string:equal? if
*home-directory*
end
then
::word "+back+" string:equal? if
".."
end
then
::word +word+? not if
::word
end
then
::word +word+->word poi:find if
end
then
::word
'bad-path-syntax-word awake
; define-function
#+end_src
*** word-interpreter-syntax:path
#+begin_src cicada-nymph :tangle core.cn
: bad-path-syntax-word,loop
<< -- >>
read-word
dup2 ";" string:equal? if
.s 32 .b
end
then
.s 32 .b
loop
; define-function
: word-interpreter-syntax:path,loop
<< cursor -- cursor >>
>:cursor
read-word >::word
";" ::word string:equal? if
:cursor
end
then
::word path-syntax-word->path dup >:length
:cursor
string->buffer!
:cursor :length add
dup
"/" string:byte
swap
set-byte
add1
loop
; define-function
: word-interpreter-syntax:path
<< literal-word:path: -- path[address, length] >>
drop2
[ << word -- >>
"* (word-interpreter-syntax:path) the following word is of bad syntax : " .s .l
" " .s .s .l
action,reset-the-stack
<< -- >>
" the rest of the words in path syntax is as following :" .s .l
" " .s bad-path-syntax-word,loop .l
end ]
'bad-path-syntax-word await
512 allocate-local-memory >:buffer
:buffer word-interpreter-syntax:path,loop >:cursor
:cursor :buffer sub >:length
*circular-string-area,current-free-address*
>:address
:buffer
:length
circular-string-area,stay
:address
:length
end
; define-function
#+end_src
*** more,syntax-rule-set:basic-REPL
#+begin_src cicada-nymph :tangle core.cn
: more,syntax-rule-set:basic-REPL
<< -- >>
syntax-rule-set:*word-interpreter*
["path:" string:equal? end]
jo word-interpreter-syntax:path
syntax-rule:add
end
; define-function
more,syntax-rule-set:basic-REPL
#+end_src
*** test
#+begin_src cicada-nymph
path: +root+ home xyh cicada core core.cn ; .s
path: +home+ cicada core core.cn ; .s
path: +back+ cicada core core.cn ; .s
path: +work+ core core.cn ; .s
path: core core.cn ; .s
"module" "module" poi:add
path: +module+ hi.cn ; .s
"module" poi:sub
<< error >>
path: +module+ hi.cn ;
#+end_src
* string
*** string:full-of-the-same-byte?
#+begin_src cicada-nymph :tangle core.cn
: string:full-of-the-same-byte?
<< string[address, length], byte -- bool >>
>:byte
>::string
::string dup zero? if
drop2
true
end
then
string:byte :byte equal? not if
false
end
then
::string string:byte-tail
:byte
loop
; define-function
#+end_src
*** test string:full-of-the-same-byte?
#+begin_src cicada-nymph :tangle core-test.cn
: "* (testing) string:full-of-the-same-byte?" .s .l
"aaa" "a" string:byte string:full-of-the-same-byte? true?
"aba" "a" string:byte string:full-of-the-same-byte? false? add test
; test-do
#+end_src
*** string:any-word
#+begin_src cicada-nymph :tangle core.cn
: string:any-word
<< string[address, length]
function : < word[address, length] -- bool >
-- bool >>
>:function
>::string
::string string:space? if
false
end
then
::string string:word :function apply if
true
end
then
::string string:word-tail
:function
loop
; define-function
#+end_src
*** string:every-word
#+begin_src cicada-nymph :tangle core.cn
: string:every-word
<< string[address, length]
function : < word[address, length] -- bool >
-- bool >>
>:function
>::string
::string string:space? if
true
end
then
::string string:word :function apply not if
false
end
then
::string string:word-tail
:function
loop
; define-function
#+end_src
*** test string:every-word
#+begin_src cicada-nymph :tangle core-test.cn
: string:every-word,testing
<< -- >>
"no no name no"
["name" string:equal? end]
string:any-word true?
"name name name"
["name" string:equal? end]
string:every-word true? and
"name name name"
["name" string:equal? not end]
string:every-word false? and
"no no name no"
["name" string:equal? end]
string:every-word false? and test
end
; test-function
: "* (testing) string:every-word" .s .l
string:every-word,testing
; test-do
#+end_src
*** string:word-end-back
#+begin_src cicada-nymph :tangle core.cn
: string:word-end-back
<< string[address, length] -- string[address, length] >>
dup zero? if
<<
no error handling
the same empty-string is returned
>>
end
then
dup2 string:byte-back
string:byte space-byte? not if
end
then
string:byte-back
loop
; define-function
#+end_src
*** string:word-begin-back
#+begin_src cicada-nymph :tangle core.cn
: string:word-begin-back,loop
<< string[address, length] -- string[address, length] >>
dup zero? if
<<
no error handling
the current empty-string is returned
>>
end
then
dup2 string:byte-back
string:byte space-byte? if
end
then
dup2 string:byte-back
string:byte bar-ket-byte? if
end
then
string:byte-back
loop
; define-function
: string:word-begin-back
<< string[address, length] -- string[address, length] >>
dup zero? if
<<
no error handling
the same empty-string is returned
>>
end
then
dup2 string:byte-back
string:byte bar-ket-byte? if
string:byte-back
end
then
string:word-begin-back,loop
end
; define-function
#+end_src
*** string:word-back
#+begin_src cicada-nymph :tangle core.cn
: string:word-back
<< string[address, length] -- string[address, length] >>
string:word-end-back
string:word-begin-back
end
; define-function
#+end_src
*** test string:word-back
#+begin_src cicada-nymph :tangle core-test.cn
: "* (testing) string:word-back" .s .l
" aaa aaa aaa"
string:word-tail dup2 " aaa aaa" string:equal? test
string:word-back dup2 "aaa aaa aaa" string:equal? test
string:word "aaa" string:equal? test
; test-do
#+end_src
* reading-stack
*** unread-word
#+begin_src cicada-nymph :tangle core.cn
: unread-word
<< -- >>
pop-reading-stack
string:word-back
push-reading-stack
end
; define-function
#+end_src
*** test
#+begin_src cicada-nymph
: unread-word,test
<< -- >>
"type a word : " .s
read-word "* read-word : " .s .s .l
unread-word
read-word "* read-word again : " .s .s .l
unread-word
read-word "* read-word again : " .s .s .l
end
; define-function
unread-word,test
#+end_src
* 記 模塊
*** 元數據 之 語法
* 舉例
#+begin_src cicada-nymph
:::::::::
import: combinator math
module: assembler
do: "assembler loaded" .s .l
=========
#+end_src
* 元數據中所包含的信息應該只和如何運行這個程序有關
因爲其他信息可能會在各個文件中重複
這些可能重複的信息應該另行保存
* 有了 元數據 之後
就可以對文件實現相對豐富的謂詞
* 元數據 中 所能包含的信息類型
還有聲明這些信息的語法
都是可以擴展的
* 語法關鍵詞都形如 "word:"
每次通過找下一個 "word:" 來確定其截止位置
* 遇不被識別的 "word:"
就忽略 而找到下一個 "word:"
*** 減載
* 或者說 撤銷加載 (unload)
它利用 (undo) 來實現
*** 加載棧
* 加載棧 記錄
1. 所有被加載的模塊的信息[模塊元數據字符串]
2. 模塊被加載的順序
3. 被加載的模塊是被直接加載還是間接加載
4. 時間 路徑 等等 其他根系統狀態有關的元數據
* (import) 就利用了這些信息
用以聞訊
同時
這些信息 也可以幫助實現詳細的 report
*** 模塊命名棧 與 全局命名棧
* 應該用兩種 命名棧
全局命名棧[global-naming-stack] 所有名字都沒有 模塊前綴
模塊命名棧[module-naming-stack] 所有名字都有 模塊前綴
* 加載模塊時入 global-naming-stack
之後統一移到 module-naming-stack
這樣就不必更改 定義者 的接口了
定義者 只要向 global-naming-stack 中入值 就行了
根 module-naming-stack 有關的操作 由其他函數 另行完成
*** 模塊與文件一一對應
* 要求 模塊與文件一一對應
這種 對應關係 影響對模塊機制的理解與使用
* 在啓動時
解釋器不會加載 core 之外的任何 module
* 所加載者 爲模塊 而非文件
不用路徑來加載模塊
而預先登記其路徑 然後直接通過模塊名來加載
* 我提供 命令行函數 來幫助在啓動時加載模塊
*** 循環引入
* 爲了處理循環引入
我需要一個 importing-stack
用以記錄 模塊之網中 由一點之引入所形成的有向路
只要在增添新的有向邊的時候 不要形成圈 就行了
* module-naming-stack
*** note module-naming-stack
* (define-*) push
(undo) pop
*** note name-record
* *module-naming-stack* contain name-record
* structure
| name-record | old-jo |
| | name |
| | new-jo |
*** *module-naming-stack*
#+begin_src cicada-nymph :tangle core.cn
100 1024 mul
: module-naming-stack:*size*
; define-variable,with-tos
3 *cell-size* mul
: module-naming-stack:*unit*
; define-variable,with-tos
module-naming-stack:*size*
module-naming-stack:*unit* mul allocate-memory
: *module-naming-stack*
; define-variable,with-tos
*module-naming-stack*
: module-naming-stack:*pointer*
; define-variable,with-tos
#+end_src
* moi
*** note
* like
*** *module-directory*
* one directory to store the name path record
"/home//.cicada/module"
#+begin_src cicada-nymph :tangle core.cn
: *module-directory,user,address*
512 allocate-memory
; define-variable
: *module-directory*
*home-directory* "/.cicada/moi"
*module-directory,user,address*
2 n-string->buffer!
*module-directory,user,address* swap
; define-variable
#+end_src
*** moi:find
* note that
this function uses *circular-string-area*
#+begin_src cicada-nymph :tangle core.cn
: moi:find
<< name[address, length]
-- path[address, length], true
-- false >>
>::name
512 allocate-local-memory >:buffer
*module-directory* "/" ::name "/path"
:buffer
4 n-string->buffer! >:length
:buffer :length
path:file? not if
false
end
then
512 allocate-local-memory >:read-buffer
:read-buffer 512
:buffer :length
file:read >:read-length
*circular-string-area,current-free-address*
>:path-address
:read-buffer :read-length
circular-string-area,stay
:path-address
:read-length
true
end
; define-function
#+end_src
*** moi:add
#+begin_src cicada-nymph :tangle core.cn
: moi:add
<< name[address, length], relative-path[address, length] -- >>
>::relative-path
>::name
::relative-path path:relative? not if
"* (moi:add) the argument must be a relative-path" .s .l
" but the following is not : " .s ::relative-path .s .l
end
then
::relative-path path:file? not if
"* (moi:add) the argument must be a relative-path to a existing file" .s .l
" but the following path is not to a file : " .s ::relative-path .s .l
end
then
::name moi:find if
"* (moi:add) can not add" .s .l
" for the following module already exist : " .s ::name .s .l
" name is use as the following directory's name : " .s .s .l
end
then
512 allocate-local-memory >:buffer
*module-directory* "/" ::name
:buffer
3 n-string->buffer!
>:length
:buffer :length
directory:create
*module-directory* "/" ::name "/path"
:buffer
4 n-string->buffer!
>:length
:buffer :length
file:create
512 allocate-local-memory >:address,full-path
work-directory:get "/" ::relative-path
:address,full-path
3 n-string->buffer! >:length,full-path
:address,full-path :length,full-path
:buffer :length
file:write
end
; define-function
#+end_src
*** moi:sub
#+begin_src cicada-nymph :tangle core.cn
: moi:sub
<< name[address, length] -- >>
>::name
::name moi:find not if
"* (moi:sub) can not sub" .s .l
" for the following module does not exist : " .s ::name .s .l
end
then
>::named-directory
512 allocate-local-memory >:buffer
*module-directory* "/" ::name "/path"
:buffer
4 n-string->buffer! >:length
:buffer :length
file:remove
*module-directory* "/" ::name
:buffer
3 n-string->buffer!
>:length
:buffer :length
directory:remove
end
; define-function
#+end_src
*** moi:up
#+begin_src cicada-nymph :tangle core.cn
: moi:up
<< name[address, length], relative-path[address, length] -- >>
>::relative-path
>::name
::relative-path path:relative? not if
"* (moi:up) the argument must be a relative-path" .s .l
" but the following is not : " .s ::relative-path .s .l
end
then
::relative-path path:file? not if
"* (moi:up) the argument must be a relative-path to a existing file" .s .l
" but the following file is not exist : " .s ::relative-path .s .l
end
then
::name moi:find not if
"* (moi:up) can not up" .s .l
" for the following module does not exist : " .s ::name .s .l
end
then
>::named-directory
512 allocate-local-memory >:buffer
*module-directory* "/" ::name "/path"
:buffer
4 n-string->buffer! >:length
512 allocate-local-memory >:address,full-path
work-directory:get "/" ::relative-path
:address,full-path
3 n-string->buffer! >:length,full-path
:address,full-path :length,full-path
:buffer :length
file:write
end
; define-function
#+end_src
*** moi:list
#+begin_src cicada-nymph :tangle core.cn
: moi:list
<< -- >>
*module-directory*
[ << -- >>
+getdents64,type+ get-byte
4 equal? if
512 allocate-local-memory >:path-buffer
+getdents64,name+
dup 256
0 string:find-byte
drop << drop 0 >>
over sub >::name
".." ::name string:equal? if
end
then
"." ::name string:equal? if
end
then
" * " .s ::name .s .l
" " .s
*module-directory* "/" ::name "/path"
:path-buffer
4 n-string->buffer! >:path-length
512 allocate-local-memory >:reading-buffer
:reading-buffer 512
:path-buffer :path-length
file:read >:reading-length
:reading-buffer :reading-length
.s .l
then
end ]
directory:map
end
; define-function
#+end_src
*** moi:help
#+begin_src cicada-nymph :tangle core.cn
: moi:help
<< -- >>
"* (moi:help)" .s .l
" * cn moi add " .s .l
" * cn moi sub " .s .l
" * cn moi up " .s .l
" * cn moi find " .s .l
" * cn moi list" .s .l
end
; define-function
#+end_src
*** test
#+begin_src cicada-nymph
"test-cicada-play" "./play" moi:add
"test-cicada-play" moi:find
if .s .l
else "not found" .s .l
then
"test-cicada-play-2" "./play-2" moi:add
"test-cicada-play-2" moi:find
if .s .l
else "not found" .s .l
then
"test-cicada-play" "./contribution" moi:up
"test-cicada-play" moi:find
if .s .l
else "not found" .s .l
then
"test-cicada-play" moi:sub
"test-cicada-play" moi:find
if .s .l
else "not found" .s .l
then
moi:list
moi:help
#+end_src
* module-stack & module-info
*** 記 用法
* 遞歸引入
返回時入此棧
* 其中保存的值用於問詢引入的模塊之狀態
比如 記錄是否帶有測試加載
比如 記錄測試成功與失敗的次數
*** *module-stack*
#+begin_src cicada-nymph :tangle core.cn
10 1024 mul
: module-stack:*size*
; define-variable,with-tos
8 *cell-size* mul
: module-stack:*unit*
; define-variable,with-tos
module-stack:*size*
module-stack:*unit* mul allocate-memory
: *module-stack*
; define-variable,with-tos
*module-stack*
: module-stack:*pointer*
; define-variable,with-tos
#+end_src
*** note
* *module-stack* contain module-info
* structure
| module-info | meta-string address |
| | meta-string length |
| | name |
| | name-record-begin |
| | name-record-end |
| | tested-flag |
| | success-counter |
| | fail-counter |
*** module-info:[get|set]-meta-string
#+begin_src cicada-nymph :tangle core.cn
: module-info:get-meta-string
<< module-info -- meta-string[address, length] >>
2 n-get
end
; define-function
: module-info:set-meta-string
<< meta-string[address, length], module-info -- >>
xx|swap|x make-string x|swap|xx
2 n-set
end
; define-function
#+end_src
*** module-info:[get|set]-name
#+begin_src cicada-nymph :tangle core.cn
: module-info:get-name
<< module-info -- name >>
*cell-size* 2 mul add
get
end
; define-function
: module-info:set-name
<< name, module-info -- >>
*cell-size* 2 mul add
set
end
; define-function
#+end_src
*** module-info:[get|set]-name-record-begin
#+begin_src cicada-nymph :tangle core.cn
: module-info:get-name-record-begin
<< module-info -- name >>
*cell-size* 3 mul add
get
end
; define-function
: module-info:set-name-record-begin
<< name, module-info -- >>
*cell-size* 3 mul add
set
end
; define-function
#+end_src
*** module-info:[get|set]-name-record-end
#+begin_src cicada-nymph :tangle core.cn
: module-info:get-name-record-end
<< module-info -- name >>
*cell-size* 4 mul add
get
end
; define-function
: module-info:set-name-record-end
<< name, module-info -- >>
*cell-size* 4 mul add
set
end
; define-function
#+end_src
*** module-info:[get|set]-tested-flag
#+begin_src cicada-nymph :tangle core.cn
: module-info:get-tested-flag
<< module-info -- name >>
*cell-size* 5 mul add
get
end
; define-function
: module-info:set-tested-flag
<< name, module-info -- >>
*cell-size* 5 mul add
set
end
; define-function
#+end_src
*** module-info:[get|set|inc]-success-counter
#+begin_src cicada-nymph :tangle core.cn
: module-info:get-success-counter
<< module-info -- name >>
*cell-size* 6 mul add
get
end
; define-function
: module-info:set-success-counter
<< name, module-info -- >>
*cell-size* 6 mul add
set
end
; define-function
: module-info:inc-success-counter
<< module-info -- >>
*cell-size* 6 mul add
1 swap
add-set
end
; define-function
#+end_src
*** module-info:[get|set|inc]-fail-counter
#+begin_src cicada-nymph :tangle core.cn
: module-info:get-fail-counter
<< module-info -- name >>
*cell-size* 7 mul add
get
end
; define-function
: module-info:set-fail-counter
<< name, module-info -- >>
*cell-size* 7 mul add
set
end
; define-function
: module-info:inc-fail-counter
<< module-info -- >>
*cell-size* 7 mul add
1 swap
add-set
end
; define-function
#+end_src
*** module-stack:find
* from the base to the pointer
#+begin_src cicada-nymph :tangle core.cn
: module-stack:find,loop
<< name, cursor
-- module-info, true
-- false >>
dup module-stack:*pointer* equal? if
drop2
false
end
then
>:cursor
>:name
:cursor module-info:get-name
:name equal? if
:cursor
true
end
then
:name
:cursor module-stack:*unit* add
loop
; define-function
: module-stack:find
<< name
-- module-info, true
-- false >>
*module-stack*
module-stack:find,loop
end
; define-function
#+end_src
* importing-stack & importing-record
*** 記 用法
* 遞歸引入
展開時入此棧
返回時出此棧
* 其中保存的值
在 eval-string 的過程中可以用到
比如 探測循環引入
比如 記錄當前的模塊是否帶測試引入
*** *importing-stack* & *testing-flag*
#+begin_src cicada-nymph :tangle core.cn
10 1024 mul
: importing-stack:*size*
; define-variable,with-tos
2 *cell-size* mul
: importing-stack:*unit*
; define-variable,with-tos
*cell-size* allocate-memory drop
*cell-size* allocate-memory
: *testing-flag*
; define-variable,with-tos
importing-stack:*size*
importing-stack:*unit* mul allocate-memory
: *importing-stack*
; define-variable,with-tos
*importing-stack*
: importing-stack:*pointer*
; define-variable,with-tos
#+end_src
*** note
* structure
| importing-record | name |
| | testing-flag |
*** importing-record:[get|set]-name
#+begin_src cicada-nymph :tangle core.cn
: importing-record:get-name
<< module-info -- name >>
get
end
; define-function
: importing-record:set-name
<< name, module-info -- >>
set
end
; define-function
#+end_src
*** importing-record:[get|set]-testing-flag
#+begin_src cicada-nymph :tangle core.cn
: importing-record:get-testing-flag
<< module-info -- bool >>
*cell-size* add get
end
; define-function
: importing-record:set-testing-flag
<< bool, module-info -- >>
*cell-size* add set
end
; define-function
#+end_src
*** importing-stack:find
* from the base to the pointer
#+begin_src cicada-nymph :tangle core.cn
: importing-stack:find,loop
<< name, cursor
-- importing-record, true
-- false >>
dup importing-stack:*pointer* equal? if
drop2
false
end
then
>:cursor
>:name
:cursor importing-record:get-name
:name equal? if
:cursor
true
end
then
:name
:cursor importing-stack:*unit* add
loop
; define-function
: importing-stack:find
<< name
-- importing-record, true
-- false >>
*importing-stack*
importing-stack:find,loop
end
; define-function
#+end_src
*** importing-stack:drop
#+begin_src cicada-nymph :tangle core.cn
: importing-stack:drop
<< -- >>
importing-stack:*unit* address importing-stack:*pointer* sub-set
end
; define-function
#+end_src
*** t
#+begin_src cicada-nymph :tangle core.cn
: t
<< -- >>
*testing-flag* get if
0 *testing-flag* set
"* (testing) *testing-flag* off" .s .l
end
else
1 *testing-flag* set
"* (testing) *testing-flag* on" .s .l
end
then
; define-function
#+end_src
* global-naming-stack & module-naming-stack
*** ---------------------------------
*** 記 接口
* 每個 模塊 都對應於 module-naming-stack 中的兩個 name-record
一個開始
一個結束
因此接口就要圍繞這對值來設計
* undo 中關於 global-naming-stack 和 module-naming-stack 的部分
可以利用這裏的接口
* (clear-naming)
name-record-begin <-- name-record-end
(prefix-naming)
name-record-begin --> name-record-end
(expose-naming)
name-record-begin --> name-record-end
*** ---------------------------------
*** module-naming-stack:record-jo
#+begin_src cicada-nymph :tangle core.cn
: module-naming-stack:record-jo
<< jo, name -- >>
dup name,get-jo
module-naming-stack:*pointer* name-record:set-old-jo
dup2 name,set-jo
module-naming-stack:*pointer* name-record:set-name
module-naming-stack:*pointer* name-record:set-new-jo
module-naming-stack:*unit* address module-naming-stack:*pointer* add-set
end
; define-function
#+end_src
*** module-naming-stack:delete-last-record
#+begin_src cicada-nymph :tangle core.cn
: module-naming-stack:delete-last-record
<< -- >>
module-naming-stack:*unit*
address module-naming-stack:*pointer*
sub-set
module-naming-stack:*pointer* name-record:get-old-jo
module-naming-stack:*pointer* name-record:get-name
name,set-jo
end
; define-function
#+end_src
*** ---------------------------------
*** global-naming-stack:clear-naming
#+begin_src cicada-nymph :tangle core.cn
: global-naming-stack:clear-naming
<< name-record-begin, name-record-end -- >>
dup2 equal? if
drop2
end
then
global-naming-stack:*unit* sub
dup >:name-record
:name-record name-record:get-old-jo
:name-record name-record:get-name
name,set-jo
loop
; define-function
#+end_src
*** module-naming-stack:clear-naming
#+begin_src cicada-nymph :tangle core.cn
: module-naming-stack:clear-naming
<< name-record-begin, name-record-end -- >>
dup2 equal? if
drop2
end
then
module-naming-stack:*unit* sub
dup >:name-record
:name-record name-record:get-old-jo
:name-record name-record:get-name
name,set-jo
loop
; define-function
#+end_src
*** ---------------------------------
*** global-naming-stack:prefix-naming
#+begin_src cicada-nymph :tangle core.cn
: global-naming-stack:prefix-naming
<< name-record-begin, name-record-end, prefix[name-index] -- >>
>:prefix
>:end
>:begin
:end :begin equal? if
end
then
512 allocate-local-memory >:buffer
:prefix name->string " " :begin name-record:get-name name->string
:buffer 3 n-string->buffer! >:length
:begin name-record:get-new-jo
:buffer :length string->name
module-naming-stack:record-jo
:begin global-naming-stack:*unit* add
:end
:prefix
loop
; define-function
#+end_src
*** module-naming-stack:expose-naming
#+begin_src cicada-nymph :tangle core.cn
: module-naming-stack:expose-naming
<< name-record-begin, name-record-end -- >>
>:end
>:begin
:end :begin equal? if
end
then
:begin name-record:get-new-jo
:begin name-record:get-name
name->string
string:word-tail string:byte-tail
string->name
global-naming-stack:record-jo
:begin module-naming-stack:*unit* add
:end
loop
; define-function
#+end_src
*** ---------------------------------
* undo
*** 記 撤銷
* 因爲 name-hash-table 的存在
導致我實現 undo 這個特性的機制
必須是去記錄差別 而不能是記錄歷史
* 具體地
在每個 undo-point 之後
所有對 jo 的 redefine 都需要被記錄
在需要退回到這個 undo-point 之時
恢復這些被從 name-hash-table 中踢出去的 jo
* 這樣
每一個 jo 被踢出 name-hash-table 時
會存入 jo name 的對子在 undo-stack 中
* 注意
每一次重新定義都對應一次恢復
* 缺點是
這樣 在兩個 undo-point 之間 對一個 jo 的多次重複定義
就帶來了一些沒必要的恢復
* 優點是
這樣就避免了對 多次重複定義的 jo 的特殊處理
不論是在效率上
還是實現的簡潔性上
這種實現方式都是更優的
*** note global states
* jojo-area
* string-area
* name-hash-table
* global-naming-stack
* module-naming-stack
* importing-stack
* syntax-backup-area
* syntax-stack
and syntax-rule-set in it
*** *undo-stack*
#+begin_src cicada-nymph :tangle core.cn
60 1024 mul
: undo-stack:*size*
; define-variable,with-tos
7 *cell-size* mul
: undo-stack:*unit*
; define-variable,with-tos
undo-stack:*size*
undo-stack:*unit* mul allocate-memory
: *undo-stack*
; define-variable,with-tos
*undo-stack*
: undo-stack:*pointer*
; define-variable,with-tos
#+end_src
*** note undo-point
* *undo-stack* contain undo-point
* structure
| undo-point | jojo-area |
| | string-area |
| | global-naming-stack |
| | module-naming-stack |
| | syntax-backup-area |
| | number of syntax-rule-sets |
| | importing-stack |
* the undo-point used to undo
will be used to reset the pointer of undo-stack
[the current-free-address of undo-stack]
*** interface of
***** undo-point:[get|set]-jojo-area
#+begin_src cicada-nymph :tangle core.cn
: undo-point:get-jojo-area
<< undo-point -- jojo-area current-free-address >>
get
end
; define-function
: undo-point:set-jojo-area
<< jojo-area current-free-address, undo-point -- >>
set
end
; define-function
#+end_src
***** undo-point:[get|set]-string-area
#+begin_src cicada-nymph :tangle core.cn
: undo-point:get-string-area
<< undo-point -- jojo-area current-free-address >>
*cell-size* add get
end
; define-function
: undo-point:set-string-area
<< jojo-area current-free-address, undo-point -- >>
*cell-size* add set
end
; define-function
#+end_src
***** undo-point:[get|set]-global-naming-stack
#+begin_src cicada-nymph :tangle core.cn
: undo-point:get-global-naming-stack
<< undo-point -- jojo-area current-free-address >>
*cell-size* 2 mul add get
end
; define-function
: undo-point:set-global-naming-stack
<< jojo-area current-free-address, undo-point -- >>
*cell-size* 2 mul add set
end
; define-function
#+end_src
***** undo-point:[get|set]-module-naming-stack
#+begin_src cicada-nymph :tangle core.cn
: undo-point:get-module-naming-stack
<< undo-point -- jojo-area current-free-address >>
*cell-size* 3 mul add get
end
; define-function
: undo-point:set-module-naming-stack
<< jojo-area current-free-address, undo-point -- >>
*cell-size* 3 mul add set
end
; define-function
#+end_src
***** undo-point:[get|set]-syntax-backup-area
#+begin_src cicada-nymph :tangle core.cn
: undo-point:get-syntax-backup-area
<< undo-point -- jojo-area current-free-address >>
*cell-size* 4 mul add get
end
; define-function
: undo-point:set-syntax-backup-area
<< jojo-area current-free-address, undo-point -- >>
*cell-size* 4 mul add set
end
; define-function
#+end_src
***** undo-point:[get|set]-number-of-syntax-rule-sets
#+begin_src cicada-nymph :tangle core.cn
: undo-point:get-number-of-syntax-rule-sets
<< undo-point -- jojo-area current-free-address >>
*cell-size* 5 mul add get
end
; define-function
: undo-point:set-number-of-syntax-rule-sets
<< jojo-area current-free-address, undo-point -- >>
*cell-size* 5 mul add set
end
; define-function
#+end_src
***** undo-point:[get|set]-importing-stack
#+begin_src cicada-nymph :tangle core.cn
: undo-point:get-importing-stack
<< undo-point -- jojo-area current-free-address >>
*cell-size* 6 mul add get
end
; define-function
: undo-point:set-importing-stack
<< jojo-area current-free-address, undo-point -- >>
*cell-size* 6 mul add set
end
; define-function
#+end_src
*** *syntax-backup-area*
#+begin_src cicada-nymph :tangle core.cn
20 1024 mul
*cell-size* mul
: *syntax-backup-area,size*
; define-variable,with-tos
*syntax-backup-area,size* allocate-memory
: *syntax-backup-area*
; define-variable,with-tos
*syntax-backup-area*
: *syntax-backup-area,current-free-address*
; define-variable,with-tos
#+end_src
*** undo-point:create
***** 記
* 將 undo-point 這個數據結構入 undo-stack
並返回剛入棧的數據結構的地址
***** undo-point:create,copy-syntax,one-syntax-rule-set
#+begin_src cicada-nymph :tangle core.cn
: undo-point:create,copy-syntax,one-syntax-rule-set
<< syntax-rule-set -- >>
>:syntax-rule-set
:syntax-rule-set syntax-rule-set:get-border >:border
:border :syntax-rule-set sub
*cell-size* div >:n
:syntax-rule-set
*syntax-backup-area,current-free-address* set
*cell-size* address *syntax-backup-area,current-free-address* add-set
:n
*syntax-backup-area,current-free-address* set
*cell-size* address *syntax-backup-area,current-free-address* add-set
:syntax-rule-set
:n n-get
*syntax-backup-area,current-free-address*
:n n-set
*cell-size* :n mul
address *syntax-backup-area,current-free-address* add-set
end
; define-function
#+end_src
***** undo-point:create,copy-syntax
#+begin_src cicada-nymph :tangle core.cn
: undo-point:create,copy-syntax
<< cursor -- >>
dup syntax-stack:*pointer* equal? if
drop
end
then
dup get undo-point:create,copy-syntax,one-syntax-rule-set
*cell-size* add
loop
; define-function
#+end_src
***** undo-point:create
#+begin_src cicada-nymph :tangle core.cn
: undo-point:create
<< -- undo-point >>
undo-stack:*pointer*
>:undo-point
undo-stack:*unit*
address undo-stack:*pointer*
add-set
*jojo-area,current-free-address*
:undo-point
undo-point:set-jojo-area
*string-area,current-free-address*
:undo-point
undo-point:set-string-area
global-naming-stack:*pointer*
:undo-point
undo-point:set-global-naming-stack
module-naming-stack:*pointer*
:undo-point
undo-point:set-module-naming-stack
importing-stack:*pointer*
:undo-point
undo-point:set-importing-stack
*syntax-backup-area,current-free-address*
:undo-point
undo-point:set-syntax-backup-area
syntax-stack:*address*
undo-point:create,copy-syntax
syntax-stack:*pointer*
syntax-stack:*address* sub
*cell-size* div
:undo-point
undo-point:set-number-of-syntax-rule-sets
:undo-point
end
; define-function
#+end_src
*** undo-point:restore
***** undo-point:restore-jojo-area
#+begin_src cicada-nymph :tangle core.cn
: undo-point:restore-jojo-area
<< undo-point -- >>
undo-point:get-jojo-area
address *jojo-area,current-free-address*
set
end
; define-function
#+end_src
***** undo-point:restore-string-area
#+begin_src cicada-nymph :tangle core.cn
: undo-point:restore-string-area
<< undo-point -- >>
undo-point:get-string-area
address *string-area,current-free-address*
set
end
; define-function
#+end_src
***** undo-point:restore-global-naming-stack
#+begin_src cicada-nymph :tangle core.cn
: undo-point:restore-global-naming-stack
<< undo-point -- >>
undo-point:get-global-naming-stack >:old-record
:old-record
global-naming-stack:*pointer*
global-naming-stack:clear-naming
:old-record address global-naming-stack:*pointer* set
end
; define-function
#+end_src
***** undo-point:restore-module-naming-stack
#+begin_src cicada-nymph :tangle core.cn
: undo-point:restore-module-naming-stack
<< undo-point -- >>
undo-point:get-module-naming-stack >:old-record
:old-record
module-naming-stack:*pointer*
module-naming-stack:clear-naming
:old-record address module-naming-stack:*pointer* set
end
; define-function
#+end_src
***** 記 語法棧的備份
* 複製出去的時候 從頭到尾[從棧底到棧頂]掃描 語法棧
複製回來的時候 從頭到尾掃描 語法備份區
* 規則集 本身做爲數據結構的存在是
| | border |
|----------+-----------|
| syntax-rule-set | predicate |
| | function |
|----------+-----------|
| | predicate |
| | function |
|----------+-----------|
| | ... |
* 語法棧中的每一個 規則集 在備份中的存在是
| address |
| length |
| jo |
| jo |
| ... |
此處把 jo 按順序複製回 address 所代表的 規則集
然後重置 current-free-address 就行了
並不必知道 jo 的語義
***** undo-point:restore-syntax-backup-area,set-syntax
#+begin_src cicada-nymph :tangle core.cn
: undo-point:restore-syntax-backup-area,set-syntax
<< cursor, syntax-rule-set-copy, number-of-syntax-rule-sets -- cursor >>
dup zero? if
drop2
end
then
>:number-of-syntax-rule-sets
>:syntax-rule-set-copy
>:cursor
:syntax-rule-set-copy get >:syntax-rule-set
:syntax-rule-set-copy *cell-size* add get >:n
:syntax-rule-set :cursor set
:syntax-rule-set-copy *cell-size* 2 mul add
:n n-get
:syntax-rule-set
:n n-set
*cell-size*
:n mul
:syntax-rule-set add
:syntax-rule-set syntax-rule-set:set-border
:cursor *cell-size* add
:syntax-rule-set-copy *cell-size* :n 2 add mul add
:number-of-syntax-rule-sets sub1
loop
; define-function
#+end_src
***** undo-point:restore-syntax-backup-area
#+begin_src cicada-nymph :tangle core.cn
: undo-point:restore-syntax-backup-area
<< undo-point -- >>
>:undo-point
:undo-point undo-point:get-syntax-backup-area >:old-address
:undo-point undo-point:get-number-of-syntax-rule-sets >:number-of-syntax-rule-sets
syntax-stack:*address*
:old-address
:number-of-syntax-rule-sets
undo-point:restore-syntax-backup-area,set-syntax >:cursor
:cursor
address syntax-stack:*pointer*
set
:old-address
address *syntax-backup-area,current-free-address*
set
end
; define-function
#+end_src
***** undo-point:restore-importing-stack
#+begin_src cicada-nymph :tangle core.cn
: undo-point:restore-importing-stack
<< undo-point -- >>
undo-point:get-importing-stack
address importing-stack:*pointer*
set
end
; define-function
#+end_src
***** undo-point:restore-undo-stack
#+begin_src cicada-nymph :tangle core.cn
: undo-point:restore-undo-stack
<< undo-point -- >>
address undo-stack:*pointer*
set
end
; define-function
#+end_src
*** undo
#+begin_src cicada-nymph :tangle core.cn
: undo
<< undo-point -- >>
>:undo-point
:undo-point undo-point:restore-jojo-area
:undo-point undo-point:restore-string-area
:undo-point undo-point:restore-global-naming-stack
:undo-point undo-point:restore-module-naming-stack
:undo-point undo-point:restore-syntax-backup-area
:undo-point undo-point:restore-importing-stack
:undo-point undo-point:restore-undo-stack
end
; define-function
#+end_src
*** test undo
#+begin_src cicada-nymph
undo-point:create
: *undo-point*
; define-variable,with-tos
: test,undo
<< -- >>
"testing undo" .s .l
end
; define-function
test,undo << testing undo >>
*undo-point* undo
test,undo << undefined >>
*undo-point* << undefined >>
<< with global-naming-stack >>
undo-point:create
: *undo-point*
; define-variable,with-tos
: test,undo
<< -- >>
"before undo" .s .l
end
; define-function
test,undo << before undo >>
: test,undo
<< -- >>
"after undo" .s .l
end
; define-function
test,undo << after undo >>
*undo-point* undo
test,undo << undefined >>
*undo-point* << undefined >>
#+end_src
*** test undo with syntax-stack
#+begin_src cicada-nymph
undo-point:create
: *undo-point*
; define-variable,with-tos
syntax-rule-set:*word-interpreter*
jo integer-string?
jo hi
syntax-rule:add
syntax-rule-set:*word-interpreter* push-syntax-stack
123 drop2 << hi >>
syntax-stack:*pointer*
syntax-stack:*address* sub
*cell-size* div . << 2 >>
<<
report:syntax
>>
*undo-point* undo
123 . << 123 >>
syntax-stack:*pointer*
syntax-stack:*address* sub
*cell-size* div . << 1 >>
<<
report:syntax
>>
#+end_src
*** test undo with alias
#+begin_src cicada-nymph
undo-point:create
: *undo-point*
; define-variable,with-tos
: test,undo
<< -- >>
"testing undo" .s .l
end
; define-function
"t,u" "test,undo" alias
test,undo << testing undo >>
t,u << testing undo >>
*undo-point* undo
test,undo << undefined >>
t,u << undefined >>
*undo-point* << undefined >>
<< with global-naming-stack >>
undo-point:create
: *undo-point*
; define-variable,with-tos
: test,undo
<< -- >>
"before undo" .s .l
end
; define-function
"t,u" "test,undo" alias
test,undo << before undo >>
t,u << before undo >>
: test,undo
<< -- >>
"after undo" .s .l
end
; define-function
test,undo << after undo >>
t,u << before undo >>
"t,u" "test,undo" alias
t,u << after undo >>
*undo-point* undo
test,undo << undefined >>
t,u << undefined >>
*undo-point* << undefined >>
#+end_src
* pre-module:*syntax-rule-set*
#+begin_src cicada-nymph :tangle core.cn
: pre-module:*syntax-rule-set:size*
1024 *cell-size* mul
; define-variable
<< for cursor >>
*cell-size* allocate-memory drop
: pre-module:*syntax-rule-set*
pre-module:*syntax-rule-set:size* allocate-memory
; define-variable
pre-module:*syntax-rule-set*
pre-module:*syntax-rule-set* *cell-size* sub
set
#+end_src
* syntax-rule-set:*post-module*
#+begin_src cicada-nymph :tangle core.cn
: post-module:*syntax-rule-set:size*
1024 *cell-size* mul
; define-variable
<< for cursor >>
*cell-size* allocate-memory drop
: syntax-rule-set:*post-module*
post-module:*syntax-rule-set:size* allocate-memory
; define-variable
syntax-rule-set:*post-module*
syntax-rule-set:*post-module* *cell-size* sub
set
#+end_src
* module-buffer
*** module-meta-begin-word?
#+begin_src cicada-nymph :tangle core.cn
: module-meta-begin-word?
<< string[address, length] -- bool >>
dup 6 less-than? if
drop2
false
end
then
":" string:byte
string:full-of-the-same-byte?
end
; define-function
#+end_src
*** module-meta-end-word?
#+begin_src cicada-nymph :tangle core.cn
: module-meta-end-word?
<< string[address, length] -- bool >>
dup 6 less-than? if
drop2
false
end
then
"=" string:byte
string:full-of-the-same-byte?
end
; define-function
#+end_src
*** module-meta-word?
#+begin_src cicada-nymph :tangle core.cn
: module-meta-word?
<< string[address, length] -- bool >>
dup2 module-meta-begin-word? if
drop2
true
end
then
dup2 module-meta-end-word? if
drop2
true
end
then
dup 1 less-or-equal? if
drop2
false
end
then
>:length
>:address
:address :length add sub1 get-byte >:last-byte
:address :length add sub1 sub1 get-byte >:the-byte-before-last-byte
:last-byte
":" string:byte equal? not if
false
end
then
:the-byte-before-last-byte
":" string:byte equal? if
false
end
then
true
end
; define-function
#+end_src
*** test module-meta-begin-word? & module-meta-begin-word?
#+begin_src cicada-nymph :tangle core-test.cn
: "* (testing) module-meta-begin-word? & module-meta-begin-word?" .s .l
"::::::" module-meta-begin-word? true?
"======" module-meta-end-word? true? and
":::::" module-meta-begin-word? false? and
"=====" module-meta-end-word? false? and
":::><:::" module-meta-begin-word? false? and
"===><===" module-meta-end-word? false? and test
; test-do
#+end_src
*** 記 謂詞
* 作用於 module-buffer 的函數
均假設 module-buffer 格式良好
在調用它們之前
應該利用有關謂詞保證其格式良好
* 謂詞是針對 module-buffer 的
[即 針對字符串的]
而不是針對文件的
否則就會重複閱讀文件
*** module-buffer:good-format?
#+begin_src cicada-nymph :tangle core.cn
: module-buffer:good-format?
<< module-buffer[address, length] -- bool >>
dup2 string:space? if
drop2
false
end
then
dup2 string:word
module-meta-begin-word? not if
drop2
false
end
then
jo module-meta-end-word? string:any-word
end
; define-function
#+end_src
*** test module-buffer:good-format?
#+begin_src cicada-nymph :tangle core-test.cn
: "* (testing) module-buffer:good-format" .s .l
"
:::::::::
import: combinator math
module: assembler
=========
hi
kkk took my baby away!
"
module-buffer:good-format? true?
"
:::::::::
import: combinator math
module: assembler
hi
kkk took my baby away!
"
module-buffer:good-format? false? and test
; test-do
#+end_src
*** module-buffer:get-code-string
#+begin_src cicada-nymph :tangle core.cn
: module-buffer:get-code-string
<< module-buffer[address, length] -- meta-string[address, length] >>
dup2 string:word
module-meta-end-word? if
string:word-tail
end
then
string:word-tail
loop
; define-function
#+end_src
*** module-buffer:get-meta-string
#+begin_src cicada-nymph :tangle core.cn
: module-buffer:get-meta-string,loop
<< module-buffer[address, length] -- cursor >>
dup2 string:word
module-meta-end-word? if
string:word-tail
drop
end
then
string:word-tail
loop
; define-function
: module-buffer:get-meta-string
<< module-buffer[address, length] -- meta-string[address, length] >>
dup2 module-buffer:get-meta-string,loop >:cursor
drop >:address
:address
:cursor :address sub
end
; define-function
#+end_src
*** test module-buffer:get-meta-string
#+begin_src cicada-nymph :tangle core-test.cn
: "* (testing) module-buffer:get-meta-string" .s .l
"
:::::::::
import: combinator math
module: assembler
=========
hi
kkk took my baby away!
"
module-buffer:get-meta-string
"
:::::::::
import: combinator math
module: assembler
========="
string:equal? test
; test-do
#+end_src
* import & load & load-with-test
*** 記 避免相互遞歸函數
* 沒有相互遞歸函數 (load) (import) 不可相互調用
加載[load] 不是遞歸函數 而待
引入[import] 是遞歸函數 而覺
* 分析一下遞歸函數
每次分析遞歸函數 就是要知道
1. 如何展開 每個遞歸調用就是展開
展開就是
返回棧增加一珠珠
分配內存給局部數據
2. 如何收回 每次函數退出就是收回
3. 比如
pre-function
recur
post-function
end
其中 pre-function 是展開過程中調用的函數 調用它們的順序是 珠珠 入棧的順序
而 post-function 是收回過程中調用的函數 調用它們的順序是 珠珠 出棧的順序
考錄 返回棧 之變化情況就很清楚啦
這次
1. 展開
入 引入棧
2. 遞歸
遞歸發生在 對語法關鍵詞 "import:" 的處理過程中
3. 返回
入 加載棧
解釋代碼
*** name->module-prefix
#+begin_src cicada-nymph :tangle core.cn
: name->module-prefix
<< name -- module-prefix >>
>:name
512 allocate-local-memory >:buffer
"|" :name name->string "|"
:buffer
3 n-string->buffer! >:length
:buffer
:length
string->name
end
; define-function
#+end_src
*** import
#+begin_src cicada-nymph :tangle core.cn
: import
<< module-name-string[address, length] -- >>
>::module-name-string
::module-name-string string->name >:module-name-index
:module-name-index name->module-prefix >:module-prefix
:module-name-index module-stack:find if
drop
end
then
:module-name-index importing-stack:find if
"* (import) circular import of : " .s ::module-name-string .s .l
'fail-to-load awake
then
::module-name-string moi:find not if
"* (import) can not find module : " .s ::module-name-string .s .l
'fail-to-load awake
then
>::module-path
64 1024 mul allocate-local-memory >:buffer
:buffer
64 1024 mul
::module-path
file:read >:length
:buffer :length module-buffer:good-format? not if
"* (import) fail to import module : " .s ::module-name-string .s .l
" for the file is not well formated cicada-nymph source code" .s .l
'fail-to-load awake
then
:buffer :length module-buffer:get-meta-string >::meta-string
:buffer :length module-buffer:get-code-string >::code-string
false
module-stack:*pointer*
module-info:set-tested-flag
false
importing-stack:*pointer*
importing-record:set-testing-flag
:module-name-index
importing-stack:*pointer*
importing-record:set-name
importing-stack:*unit* address importing-stack:*pointer* add-set
global-naming-stack:*pointer* >:global-name-record-before-import
pre-module:*syntax-rule-set* push-syntax-stack
::meta-string eval-string
drop-syntax-stack
global-naming-stack:*pointer* >:global-name-record-begin
syntax-rule-set:*word-interpreter* push-syntax-stack
::code-string eval-string
drop-syntax-stack
global-naming-stack:*pointer* >:global-name-record-end
syntax-rule-set:*post-module* push-syntax-stack
::meta-string eval-string
drop-syntax-stack
importing-stack:drop
module-naming-stack:*pointer* >:module-name-record-begin
:global-name-record-begin
:global-name-record-end
:module-prefix
global-naming-stack:prefix-naming
module-naming-stack:*pointer* >:module-name-record-end
:global-name-record-before-import
global-naming-stack:*pointer*
global-naming-stack:clear-naming
:global-name-record-before-import address global-naming-stack:*pointer* set
:module-name-record-begin
module-stack:*pointer*
module-info:set-name-record-begin
:module-name-record-end
module-stack:*pointer*
module-info:set-name-record-end
::meta-string
module-stack:*pointer*
module-info:set-meta-string
:module-name-index
module-stack:*pointer*
module-info:set-name
module-stack:*unit* address module-stack:*pointer* add-set
end
; define-function
#+end_src
*** module-syntax:unknow-meta-word
#+begin_src cicada-nymph :tangle core.cn
: module-syntax:unknow-meta-word,loop
<< -- >>
read-word module-meta-word? if
unread-word
end
then
loop
; define-function
: module-syntax:unknow-meta-word
<< meta-word -- >>
drop2
module-syntax:unknow-meta-word,loop
end
; define-function
#+end_src
*** pre-module-syntax
***** meta-literal-word:import?
#+begin_src cicada-nymph :tangle core.cn
: meta-literal-word:import?
<< word[address, length] -- bool >>
"import:" string:equal?
end
; define-function
#+end_src
***** pre-module-syntax:import
* import module and expose-naming
one by one
#+begin_src cicada-nymph :tangle core.cn
: pre-module-syntax:import,loop
<< -- unknow >>
read-word >::word
::word string->name >:name
::word module-meta-word? if
unread-word
end
then
::word import
:name module-stack:find not if
"* (pre-module-syntax:import,loop) after import module : " .s
:name name->string .s .l
" still can not find it in the module-stack" .s .l
end
then
>:module-info
:module-info module-info:get-name-record-begin
:module-info module-info:get-name-record-end
module-naming-stack:expose-naming
loop
; define-function
: pre-module-syntax:import
<< meta-literal-word:import -- unknow >>
drop2
pre-module-syntax:import,loop
end
; define-function
#+end_src
***** add syntax-rule
* the order matters
#+begin_src cicada-nymph :tangle core.cn
pre-module:*syntax-rule-set*
syntax-rule-set:*word-interpreter*
syntax-rule-set:mixin
pre-module:*syntax-rule-set*
jo module-meta-word?
jo module-syntax:unknow-meta-word
syntax-rule:add
pre-module:*syntax-rule-set*
jo module-meta-begin-word?
jo drop2
syntax-rule:add
pre-module:*syntax-rule-set*
jo module-meta-end-word?
jo drop2
syntax-rule:add
pre-module:*syntax-rule-set*
jo meta-literal-word:import?
jo pre-module-syntax:import
syntax-rule:add
#+end_src
*** post-module-syntax
***** meta-literal-word:do?
#+begin_src cicada-nymph :tangle core.cn
: meta-literal-word:do?
<< word[address, length] -- bool >>
"do:" string:equal?
end
; define-function
#+end_src
***** post-module-syntax:do
#+begin_src cicada-nymph :tangle core.cn
: post-module-syntax:do,loop
<< -- >>
read-word >::word
::word module-meta-word? if
unread-word
end
then
::word word-interpreter
loop
; define-function
: post-module-syntax:do
<< meta-literal-word:do -- >>
drop2
post-module-syntax:do,loop
end
; define-function
#+end_src
***** add syntax-rule
#+begin_src cicada-nymph :tangle core.cn
syntax-rule-set:*post-module*
syntax-rule-set:*word-interpreter*
syntax-rule-set:mixin
syntax-rule-set:*post-module*
jo module-meta-word?
jo module-syntax:unknow-meta-word
syntax-rule:add
syntax-rule-set:*post-module*
jo module-meta-begin-word?
jo drop2
syntax-rule:add
syntax-rule-set:*post-module*
jo module-meta-end-word?
jo drop2
syntax-rule:add
syntax-rule-set:*post-module*
jo meta-literal-word:do?
jo post-module-syntax:do
syntax-rule:add
#+end_src
*** test
#+begin_src cicada-nymph
<< in system shell
cn moi add hi module/hi.cn
cn moi add hihi module/hihi.cn
>>
"hihi" import
hihi << undefined >>
: *test-module-info*
name hihi module-stack:find if
else
"* can not found hihi" .s .l
then
; define-variable
*test-module-info* module-info:get-meta-string .s .l
*test-module-info* module-info:get-name name->string .s .l
hihi << undefined >>
*test-module-info* module-info:get-name-record-begin
*test-module-info* module-info:get-name-record-end
module-naming-stack:expose-naming
hihi
#+end_src
*** load
#+begin_src cicada-nymph :tangle core.cn
: load
<< module-name-string[address, length] -- >>
>::module-name-string
::module-name-string
undo-point:create
reading-stack:*pointer*
<< module-name-string[address, length],
undo-point
reading-stack:*pointer*
-- >>
[ action,reset-the-stack
<< module-name-string[address, length],
undo-point
reading-stack:*pointer*
-- >>
address reading-stack:*pointer* set
undo
"* (load) can not load : " .s .s .l
end ]
'fail-to-load await
::module-name-string string->name >:module-name-index
:module-name-index name->module-prefix >:module-prefix
:module-name-index module-stack:find if
drop
"* (load) the following module is already loaded : " .s ::module-name-string .s .l
'fail-to-load awake
then
:module-name-index importing-stack:find if
"* (load) circular import of : " .s ::module-name-string .s .l
'fail-to-load awake
then
::module-name-string moi:find not if
"* (load) can not find module : " .s ::module-name-string .s .l
'fail-to-load awake
then
>::module-path
64 1024 mul allocate-local-memory >:buffer
:buffer
64 1024 mul
::module-path
file:read >:length
:buffer :length module-buffer:good-format? not if
"* (load) fail to import module : " .s ::module-name-string .s .l
" for the file is not well formated cicada-nymph source code" .s .l
'fail-to-load awake
then
:buffer :length module-buffer:get-meta-string >::meta-string
:buffer :length module-buffer:get-code-string >::code-string
false
module-stack:*pointer*
module-info:set-tested-flag
false
importing-stack:*pointer*
importing-record:set-testing-flag
:module-name-index
importing-stack:*pointer*
importing-record:set-name
importing-stack:*unit* address importing-stack:*pointer* add-set
global-naming-stack:*pointer* >:global-name-record-before-import
pre-module:*syntax-rule-set* push-syntax-stack
::meta-string eval-string
drop-syntax-stack
global-naming-stack:*pointer* >:global-name-record-begin
syntax-rule-set:*word-interpreter* push-syntax-stack
::code-string eval-string
drop-syntax-stack
global-naming-stack:*pointer* >:global-name-record-end
syntax-rule-set:*post-module* push-syntax-stack
::meta-string eval-string
drop-syntax-stack
importing-stack:drop
module-naming-stack:*pointer* >:module-name-record-begin
:global-name-record-begin
:global-name-record-end
:module-prefix
global-naming-stack:prefix-naming
module-naming-stack:*pointer* >:module-name-record-end
:global-name-record-before-import
global-naming-stack:*pointer*
global-naming-stack:clear-naming
:global-name-record-before-import address global-naming-stack:*pointer* set
:module-name-record-begin
module-stack:*pointer*
module-info:set-name-record-begin
:module-name-record-end
module-stack:*pointer*
module-info:set-name-record-end
::meta-string
module-stack:*pointer*
module-info:set-meta-string
:module-name-index
module-stack:*pointer*
module-info:set-name
module-stack:*unit* address module-stack:*pointer* add-set
drop
drop
drop2
end
; define-function
#+end_src
*** test
#+begin_src cicada-nymph
<< in system shell
cn moi add hi module/hi.cn
cn moi add hihi module/hihi.cn
>>
"hihi" load
hihi << undefined >>
: *test-module-info*
name hihi module-stack:find if
else
"* can not found hihi" .s .l
then
; define-variable
*test-module-info* module-info:get-meta-string .s .l
*test-module-info* module-info:get-name name->string .s .l
hihi << undefined >>
*test-module-info* module-info:get-name-record-begin
*test-module-info* module-info:get-name-record-end
module-naming-stack:expose-naming
hihi
report:memory
"no" load
"hihi" load
report:memory
#+end_src
*** load-with-test
#+begin_src cicada-nymph :tangle core.cn
: load-with-test
<< module-name-string[address, length] -- >>
>::module-name-string
::module-name-string
undo-point:create
reading-stack:*pointer*
<< module-name-string[address, length],
undo-point
reading-stack:*pointer*
-- >>
[ action,reset-the-stack
<< module-name-string[address, length],
undo-point
reading-stack:*pointer*
-- >>
address reading-stack:*pointer* set
undo
"* (load-with-test) can not load : " .s .s .l
end ]
'fail-to-load await
::module-name-string string->name >:module-name-index
:module-name-index name->module-prefix >:module-prefix
:module-name-index module-stack:find if
drop
"* (load-with-test) the following module is already loaded : " .s ::module-name-string .s .l
'fail-to-load awake
then
:module-name-index importing-stack:find if
"* (load-with-test) circular import of : " .s ::module-name-string .s .l
'fail-to-load awake
then
::module-name-string moi:find not if
"* (load-with-test) can not find module : " .s ::module-name-string .s .l
'fail-to-load awake
then
>::module-path
64 1024 mul allocate-local-memory >:buffer
:buffer
64 1024 mul
::module-path
file:read >:length
:buffer :length module-buffer:good-format? not if
"* (load-with-test) fail to import module : " .s ::module-name-string .s .l
" for the file is not well formated cicada-nymph source code" .s .l
'fail-to-load awake
then
:buffer :length module-buffer:get-meta-string >::meta-string
:buffer :length module-buffer:get-code-string >::code-string
true
module-stack:*pointer*
module-info:set-tested-flag
0
module-stack:*pointer*
module-info:set-success-counter
0
module-stack:*pointer*
module-info:set-fail-counter
true
importing-stack:*pointer*
importing-record:set-testing-flag
:module-name-index
importing-stack:*pointer*
importing-record:set-name
importing-stack:*unit* address importing-stack:*pointer* add-set
global-naming-stack:*pointer* >:global-name-record-before-import
pre-module:*syntax-rule-set* push-syntax-stack
::meta-string eval-string
drop-syntax-stack
global-naming-stack:*pointer* >:global-name-record-begin
syntax-rule-set:*word-interpreter* push-syntax-stack
::code-string eval-string
drop-syntax-stack
global-naming-stack:*pointer* >:global-name-record-end
syntax-rule-set:*post-module* push-syntax-stack
::meta-string eval-string
drop-syntax-stack
importing-stack:drop
module-naming-stack:*pointer* >:module-name-record-begin
:global-name-record-begin
:global-name-record-end
:module-prefix
global-naming-stack:prefix-naming
module-naming-stack:*pointer* >:module-name-record-end
:global-name-record-before-import
global-naming-stack:*pointer*
global-naming-stack:clear-naming
:global-name-record-before-import address global-naming-stack:*pointer* set
:module-name-record-begin
module-stack:*pointer*
module-info:set-name-record-begin
:module-name-record-end
module-stack:*pointer*
module-info:set-name-record-end
::meta-string
module-stack:*pointer*
module-info:set-meta-string
:module-name-index
module-stack:*pointer*
module-info:set-name
"* (load-with-test) load : " .s ::module-name-string .s .l
" success : " .s
module-stack:*pointer* module-info:get-success-counter
.i .l
" fali : " .s
module-stack:*pointer* module-info:get-fail-counter
.i .l
module-stack:*unit* address module-stack:*pointer* add-set
drop
drop
drop2
end
; define-function
#+end_src
*** test-function
#+begin_src cicada-nymph :tangle core.cn
: test-function
<< string[address, length] -- >>
importing-stack:*pointer*
importing-stack:*unit* sub
importing-record:get-testing-flag if
define-function
end
then
drop2
end
; define-function
#+end_src
*** test-variable
#+begin_src cicada-nymph :tangle core.cn
: test-variable
<< string[address, length] -- >>
importing-stack:*pointer*
importing-stack:*unit* sub
importing-record:get-testing-flag if
define-variable
end
then
drop2
end
; define-function
#+end_src
*** test-variable,with-tos
#+begin_src cicada-nymph :tangle core.cn
: test-variable,with-tos
<< string[address, length] -- >>
importing-stack:*pointer*
importing-stack:*unit* sub
importing-record:get-testing-flag if
define-variable,with-tos
end
then
drop2
end
; define-function
#+end_src
*** test-do
#+begin_src cicada-nymph :tangle core.cn
: test-do
<< string[address, length] -- >>
importing-stack:*pointer*
importing-stack:*unit* sub
importing-record:get-testing-flag if
eval-string
end
then
drop2
end
; define-function
#+end_src
*** the function test
#+begin_src cicada-nymph :tangle core.cn
: test
<< bool -- >>
if
" (success)" .s .l
module-stack:*pointer* module-info:inc-success-counter
else
" (fail)" .s .l
module-stack:*pointer* module-info:inc-fail-counter
then
end
; define-function
#+end_src
*** test
#+begin_src cicada-nymph
<< in system shell
cn moi add hi module/hi.cn
cn moi add hihi module/hihi.cn
>>
"hihi" load-with-test
hihi << undefined >>
: *test-module-info*
name hihi module-stack:find if
else
"* can not found hihi" .s .l
then
; define-variable
*test-module-info* module-info:get-meta-string .s .l
*test-module-info* module-info:get-name name->string .s .l
hihi << undefined >>
*test-module-info* module-info:get-name-record-begin
*test-module-info* module-info:get-name-record-end
module-naming-stack:expose-naming
hihi
report:memory
"no" load-with-test
"hihi" load-with-test
report:memory
#+end_src
*** test with gamber
#+begin_src cicada-nymph
"gamber" load-with-test
#+end_src
* type
* report
*** report:memory
#+begin_src cicada-nymph :tangle core.cn
: report:memory
<< -- >>
"* *un-initialized-memory*" .s .l
" * size : " .s
*un-initialized-memory,size*
. .l
" * used : " .s
*un-initialized-memory,current-free-address*
*un-initialized-memory*
sub . .l
" * free : " .s
*un-initialized-memory,size*
*un-initialized-memory,current-free-address*
*un-initialized-memory*
sub sub . .l
"* *string-area*" .s .l
" * size : " .s
*string-area,size*
. .l
" * used : " .s
*string-area,current-free-address*
*string-area*
sub . .l
" * free : " .s
*string-area,size*
*string-area,current-free-address*
*string-area*
sub sub . .l
"* *jojo-area*" .s .l
" * size : " .s
*jojo-area,size* . .l
" * used : " .s
*jojo-area,current-free-address*
*jojo-area*
sub . .l
" * free : " .s
*jojo-area,size*
*jojo-area,current-free-address*
*jojo-area*
sub sub . .l
end
; define-function
#+end_src
*** report:syntax
#+begin_src cicada-nymph :tangle core.cn
: report:syntax
<< -- >>
"* jojo-compiler:*syntax-rule-set* :" .s .l
jojo-compiler:*syntax-rule-set* syntax-rule-set:list
"* syntax-rule-set:*word-interpreter* :" .s .l
syntax-rule-set:*word-interpreter* syntax-rule-set:list
"* tos-syntax-stack :" .s .l
tos-syntax-stack syntax-rule-set:list
end
; define-function
#+end_src
*** global-naming-stack:list-by-jo-predicate
* 最後寫到珠典裏的 被最先打印出來
#+begin_src cicada-nymph :tangle core.cn
: global-naming-stack:list-by-jo-predicate,loop
<< jo-predicate, counter, cursor -- >>
dup global-naming-stack:*pointer* equal? if
drop
drop
drop
end
then
>:cursor
>:counter
>:jo-predicate
:cursor name-record:get-new-jo
:jo-predicate apply if
" " .s
:counter .i ". " .s :counter add1 >:counter
:cursor name-record:get-name name->string .s
.l
then
:jo-predicate
:counter
:cursor global-naming-stack:*unit* add
loop
; define-function
: global-naming-stack:list-by-jo-predicate
<< jo-predicate -- >>
1
*global-naming-stack*
global-naming-stack:list-by-jo-predicate,loop
end
; define-function
#+end_src
*** report:global-naming-stack
* different types of words in link
are showed separately
#+begin_src cicada-nymph :tangle core.cn
: report:global-naming-stack
<< -- >>
"* all primitive-function in global-naming-stack :" .s .l
jo primitive-function-jo?
global-naming-stack:list-by-jo-predicate
"* all function in global-naming-stack :" .s .l
jo function-jo?
global-naming-stack:list-by-jo-predicate
"* all variable in global-naming-stack :" .s .l
jo variable-jo?
global-naming-stack:list-by-jo-predicate
end
; define-function
#+end_src
*** report:system
#+begin_src cicada-nymph :tangle core.cn
: report:system
<< -- >>
"* (system) " .s
*cell-size* 8 mul .i "bit" .s
" " .s
platform .s
.l
end
; define-function
#+end_src
* hi
#+begin_src cicada-nymph :tangle core.cn
0
: *hi,random-base*
; define-variable,with-tos
: hi,random
<< -- random-number >>
0 syscall-number:*times*
1 syscall
13 mod
<<
*hi,random-base*
*hi,random-base* add1 13 mod
address *hi,random-base* set
>>
end
; define-function
: hi,say
<< number -- >>
dup 0 equal? if drop "cica cica da yaya !!!" .s .l end then
dup 1 equal? if drop "hi ^-^" .s .l end then
dup 2 equal? if drop "hello :)" .s .l end then
dup 3 equal? if drop "hey *^-^*" .s .l end then
dup 4 equal? if drop "hiya \^o^/" .s .l end then
dup 5 equal? if drop "I wish you a lovely day" .s .l end then
dup 6 equal? if drop "I wish you a lovely day { or night :P }" .s .l end then
dup 7 equal? if drop "o.o" .s .l end then
dup 8 equal? if drop "O.o" .s .l end then
dup 9 equal? if drop "o.O" .s .l end then
drop "lovely ^3^" .s .l end
; define-function
: hi
<< -- >>
hi,random
hi,say
end
; define-function
#+end_src
* help
#+begin_src cicada-nymph :tangle core.cn
: help
<< -- >>
"* helpful documentations will be written soon" .s .l
" please wait ^-^" .s .l
end
; define-function
#+end_src
* command line interface
*** command-function:unknow-function
#+begin_src cicada-nymph :tangle core.cn
: command-function:unknow-function
<< -- >>
"* (cicada-nymph) unknow command-line-function : " .s
get-command-line
string:word-tail
string:word .s .l
" good bye ^-^/" .s .l
bye
; define-function
#+end_src
*** command-function:stack-REPL
#+begin_src cicada-nymph :tangle core.cn
: command-function:stack-REPL
<< -- >>
.l
"* (cicada-nymph) " .s hi
report:system
"* (stack-REPL) is where you are now" .s .l
" eval a word print the stack" .s .l
argument-stack:pretty-print
jo stack-REPL
reset-top-level-REPL
; define-function
#+end_src
*** command-function:basic-REPL
#+begin_src cicada-nymph :tangle core.cn
: command-function:basic-REPL
<< -- >>
.l
"* (cicada-nymph) " .s hi
report:system
"* (basic-REPL) is where you are now" .s .l
" this REPL does not print any thing automaticly" .s .l
jo basic-REPL
reset-top-level-REPL
; define-function
#+end_src
*** command-function:poi
* cn poi add
* cn poi sub
* cn poi up
* cn poi find
* cn poi list
#+begin_src cicada-nymph :tangle core.cn
: command-function:poi
<< -- >>
get-command-line
string:word-tail
string:word-tail >::command-line
::command-line string:space? if
poi:help
bye
then
::command-line string:word >::sub-function-name
::command-line string:word-tail >::command-line-arguments
::sub-function-name "help" string:equal? if
poi:help
bye
then
::sub-function-name "add" string:equal? if
::command-line-arguments string:word
::command-line-arguments string:word-tail string:word
poi:add
bye
then
::sub-function-name "sub" string:equal? if
::command-line-arguments string:word
poi:sub
bye
then
::sub-function-name "up" string:equal? if
::command-line-arguments string:word
::command-line-arguments string:word-tail string:word
poi:up
bye
then
::sub-function-name "find" string:equal? if
::command-line-arguments string:word
poi:find if
.s .l
else
"no found" .s .l
then
bye
then
::sub-function-name "list" string:equal? if
poi:list
bye
then
"* (command-function:poi) meets argument that (command-function:poi) can not understand" .s .l
" it is the following command-line that is confusing (command-function:poi) :" .s .l
" " .s report:command-line .l
" to get some help info you can type :" .s .l
" cn poi help" .s .l
" good bye ^-^/" .s .l
bye
; define-function
#+end_src
*** command-function:moi
* cn module add
* cn module sub
* cn module up
* cn module find
* cn module list
#+begin_src cicada-nymph :tangle core.cn
: command-function:moi
<< -- >>
get-command-line
string:word-tail
string:word-tail >::command-line
::command-line string:space? if
moi:help
bye
then
::command-line string:word >::sub-function-name
::command-line string:word-tail >::command-line-arguments
::sub-function-name "help" string:equal? if
moi:help
bye
then
::sub-function-name "add" string:equal? if
::command-line-arguments string:word
::command-line-arguments string:word-tail string:word
moi:add
bye
then
::sub-function-name "sub" string:equal? if
::command-line-arguments string:word
moi:sub
bye
then
::sub-function-name "up" string:equal? if
::command-line-arguments string:word
::command-line-arguments string:word-tail string:word
moi:up
bye
then
::sub-function-name "find" string:equal? if
::command-line-arguments string:word
moi:find if
.s .l
else
"no found" .s .l
then
bye
then
::sub-function-name "list" string:equal? if
moi:list
bye
then
"* (command-function:moi) meets argument that (command-function:moi) can not understand" .s .l
" it is the following command-line that is confusing (command-function:moi) :" .s .l
" " .s report:command-line .l
" to get some help info you can type :" .s .l
" cn module help" .s .l
" good bye ^-^/" .s .l
bye
; define-function
#+end_src
*** command-function:load
#+begin_src cicada-nymph :tangle core.cn
: command-function:load
<< -- >>
get-command-line
string:word-tail
string:word-tail >::command-line
::command-line string:space? if
"* (command-function:load) is called with no argument" .s .l
" it should be called with a name of module" .s .l
bye
then
::command-line string:word load
bye
; define-function
#+end_src
*** command-function:load-with-test
#+begin_src cicada-nymph :tangle core.cn
: command-function:load-with-test
<< -- >>
get-command-line
string:word-tail
string:word-tail >::command-line
::command-line string:space? if
"* (command-function:load-with-test) is called with no argument" .s .l
" it should be called with a name of module" .s .l
bye
then
::command-line string:word load-with-test
bye
; define-function
#+end_src
*** command-function:no-function
#+begin_src cicada-nymph :tangle core.cn
: command-function:no-function
<< -- >>
command-function:stack-REPL
end
; define-function
#+end_src
*** command:dispatch
#+begin_src cicada-nymph :tangle core.cn
: command:dispatch
<< -- >>
get-command-line
string:word-tail
dup2 string:space? if
drop2
command-function:no-function
end
then
string:word
>::1st-word
::1st-word "basic-REPL" string:equal? if
command-function:basic-REPL
end
then
::1st-word "stack-REPL" string:equal? if
command-function:stack-REPL
end
then
::1st-word "poi" string:equal? if
command-function:poi
end
then
::1st-word "moi" string:equal? if
command-function:moi
end
then
::1st-word "load" string:equal? if
command-function:load
end
then
::1st-word "load-with-test" string:equal? if
command-function:load-with-test
end
then
command-function:unknow-function
end
; define-function
#+end_src
* *the story begin*
#+begin_src cicada-nymph :tangle core.cn
command:dispatch
#+end_src
* test
#+begin_src cicada-nymph
"core-test" load-with-test
report:system
report:memory
report:global-naming-stack
<<
report:syntax
report:command-line
report:environment-variable
>>
#+end_src