git @ Cat's Eye Technologies Kosheri / master tests / Assembly.markdown
master

Tree @master (Download .tar.gz)

Assembly.markdown @masterview markup · raw · history · blame

Kosheri Assembly

-> Functionality "Round-trip Kosheri Assembly" is implemented by shell command
-> "./assemble --asmfile %(test-body-file) --vmfile foo.kvm && ./disasm --vmfile foo.kvm --asmfile %(output-file)"

-> Tests for functionality "Round-trip Kosheri Assembly"

| NEW_AR #10
| GOTO :past_q
| :q
|           ; no need to reserve space for parameters
| GETI #0       ; local #0 = 1st parameter = a
| STDOUT
| PORTRAY
| 
| GETI #1       ; local #1 = 2nd parameter = b
| STDOUT
| PORTRAY
| 
| GETI #0
| GETI #1
| ADD_INT
| 
| YIELD #1      ; pass the result back to our caller
| RET           ; end of this function
| 
| :past_q
| 
| PUSH #1
| 
| PUSH #2
| PUSH #3
| PUSH #10      ; this function will need 4 slots: 2 args, 2 stack
| FUN :q        ; push a closure for q onto the stack
| CALL #2       ; call it with two args
| 
| PUSH #10      ; this function will need 4 slots: 2 args, 2 stack
| FUN :q        ; push a closure for q onto the stack
| CALL #2       ; call it with two args
| 
| STDOUT
| PORTRAY
| 
| HALT
= :L0
= NEW_AR #10
= GOTO :L20 
= :L4
= GETI #0
= STDOUT 
= PORTRAY 
= GETI #1
= STDOUT 
= PORTRAY 
= GETI #0
= GETI #1
= ADD_INT 
= YIELD #1
= RET 
= :L20
= PUSH #1
= PUSH #2
= PUSH #3
= PUSH #10
= FUN :L4 
= CALL #2
= PUSH #10
= FUN :L4 
= CALL #2
= STDOUT 
= PORTRAY 
= HALT 
=

Unused labels aren't produced by the disassembler.

| NEW_AR #5
| :here
| PUSH #123
| STDOUT
| PORTRAY
| HALT
= :L0
= NEW_AR #5
= PUSH #123
= STDOUT 
= PORTRAY 
= HALT 
=

Redefining a label is an error.

| NEW_AR #5
| :here
| PUSH #123
| STDOUT
| PORTRAY
| :here
| HALT
? line 6, column 6, token 'here'): Assembly Error: Label already defined.
? Assembly finished with 1 errors and 0 warnings

You can include literal terms of all kinds in an assembly file.

| NEW_AR #5
| PUSH #<tuple: THIS, IS, 1, TUPLE>
| STDOUT
| PORTRAY
| HALT
= :L0
= NEW_AR #5
= PUSH #<tuple: THIS, IS, 1, TUPLE>
= STDOUT 
= PORTRAY 
= HALT 
=

-> Functionality "Run Kosheri Assembly" is implemented by shell command
-> "./assemble --asmfile %(test-body-file) --vmfile foo.kvm >/dev/null 2>&1 && ./run --vmfile foo.kvm"

-> Tests for functionality "Run Kosheri Assembly"

Hello, world-ing

You can include literal terms of all kinds in an assembly file.

| NEW_AR #5
| PUSH #<tuple: THIS, IS, 1, TUPLE>
| STDOUT
| PORTRAY
| HALT
= <tuple: THIS, IS, 1, TUPLE>

Basic Arithmetic

Add eight to two and output the answer.

| NEW_AR #2
| PUSH #8
| PUSH #2
| ADD_INT
| STDOUT
| PORTRAY
| HALT
= 10

Subtract three from twelve and output the answer.

| NEW_AR #2
| PUSH #12
| PUSH #3
| SUB_INT
| STDOUT
| PORTRAY
| HALT
= 9

Multiply 6 by 7.

| NEW_AR #2
| PUSH #6
| PUSH #7
| MUL_INT
| STDOUT
| PORTRAY
| HALT
= 42

Divide 40 by 5.

| NEW_AR #2
| PUSH #40
| PUSH #5
| DIV_INT
| STDOUT
| PORTRAY
| HALT
= 8

Basic Looping

Count down from 11 to 1.

| NEW_AR #3
| PUSH #11  ; statically initialize our local
| :label
| GETI #0
| STDOUT
| PORTRAY
| GETI #0
| PUSH #1
| SUB_INT
| SETI #0
| GETI #0
| PUSH #0
| JNE :label
| HALT
= 1110987654321

Function calling

Call a simple function.

local q = function(a)
    print a
    return 5
end
print q(4)

| NEW_AR #5
| PUSH #0   ; move stack pointer up for one local, q
| GOTO :past_q
| :q
|       ; no need to reserve space for parameters
| GETI #0   ; local #0 = 1st parameter = a
| STDOUT
| PORTRAY
| 
| PUSH #5
| YIELD #1  ; pass the result back to our caller
| RET       ; end of this function
| 
| :past_q
| PUSH #5   ; this function will need 2 slots: 1 arg, 1 stack
| FUN :q    ; push a closure for q onto the stack
| SETI #0   ; set local #0 = q
| 
| PUSH #4   ; put argument to pass on the stack
| GETI #0   ; put function (AR) to call (activate) on the stack
| CALL #1   ; call function, with one argument
| 
| STDOUT    ; return value is on the stack.  print it
| PORTRAY
| 
| HALT
= 45

Make two calls to a function.

local q = function(a, b)
    print a
    print b
    return a + b
end
print q(1, q(2, 3))

| NEW_AR #10
| GOTO :past_q
| :q
|           ; no need to reserve space for parameters
| GETI #0       ; local #0 = 1st parameter = a
| STDOUT
| PORTRAY
| 
| GETI #1       ; local #1 = 2nd parameter = b
| STDOUT
| PORTRAY
| 
| GETI #0
| GETI #1
| ADD_INT
| 
| YIELD #1      ; pass the result back to our caller
| RET           ; end of this function
| 
| :past_q
| 
| PUSH #1
| 
| PUSH #2
| PUSH #3
| PUSH #10      ; this function will need 4 slots: 2 args, 2 stack
| FUN :q        ; push a closure for q onto the stack
| CALL #2       ; call it with two args
| 
| PUSH #10      ; this function will need 4 slots: 2 args, 2 stack
| FUN :q        ; push a closure for q onto the stack
| CALL #2       ; call it with two args
| 
| STDOUT
| PORTRAY
| 
| HALT
= 23156

Call an iterator.

local q = function()
    yield 1
    yield 3
    yield 5
end
print q()
print q()
print q()

| NEW_AR #7
| PUSH #0       ; move stack pointer up for one local, q
| GOTO :past_q
| :q
| PUSH #1
| YIELD #1  ; yield one value
| RET
| PUSH #3
| YIELD #1  ; yield another value
| RET
| PUSH #5
| YIELD #1
| RET
| 
| :past_q
| PUSH #7       ; this function will need 1 local
| FUN :q        ; push a closure for q onto the stack
| SETI #0       ; set local #0 = q
| 
| GETI #0       ; call q three times; should get a different
| CALL #0       ; result each time.
| STDOUT
| PORTRAY
| 
| GETI #0
| RESUME #0
| STDOUT
| PORTRAY
| 
| GETI #0
| RESUME #0
| STDOUT
| PORTRAY
| 
| HALT
= 135

Return a function from a function.

local f = function(a)
    print a
    local g = function(b)
        return b
    end
    return g
end
h = f(3)
print h(9)

| NEW_AR #7
| PUSH #0
| PUSH #0
| GOTO :past_f
| :f 
| GETI #0
| STDOUT
| PORTRAY
| 
| GOTO :past_g
| :g
| GETI #0
| YIELD #1
| RET
| 
| :past_g
| PUSH #7
| FUN :g
| YIELD #1
| RET
| 
| :past_f
| 
| PUSH #7       ; this function will need 1 local
| FUN :f        ; push a closure for f onto the stack
| SETI #0
| 
| PUSH #3
| GETI #0
| CALL #1               ; now we'll have a fun on the stack
| 
| SETI #1
| PUSH #9
| GETI #1
| CALL #1
| 
| STDOUT
| PORTRAY
| 
| HALT
= 39

Call a closure.

local f = function(a)
    local g = function(b)
        return a + b
    end
    return g
end
h = f(3)
print h(9)

| HALT
=

Spawn a process!

The behaviour of this might rely on multithreading details... like that we execute 100 cycles before switching.

| NEW_AR #7
| SPAWN :label
| REST
| PUSH #main
| STDOUT
| PORTRAY
| HALT
| :label
| NEW_AR #7
| PUSH #worker
| STDOUT
| PORTRAY
| HALT
= workermain