JCRS

Join Calculus flavored Rewriting System

Language

<> buffer ?r :
	<> $r push ?v , $r _none :
	 	! $r ~value $v ;
	;
	<> $r get [ ~?cb ] , $r _value ?v :
		! $cb $v ;
		! $r _none ;
	;
	! $r _none ;
;

! buffer my-buffer ;

! my-buffer push 5 ;
! my-buffer get [ io print ] ;

! creator name "florian" ;
? creator name ~?name :
	! io print $name ;
;

Example Bytecode Textual Representation

rule ??
pre-conds 1
pre-cond 2
	word $buffer
	make-var $r
post-conds 3
post-cond
	rule ??
	pre-conds 2
	pre-cond 3
		push-var $r
		word $push
		nake-var $v
	pre-cond 2
		push-var $r
		word $_none
	post-conds 1
	post-cond
		fact 9
			push-var $r
			word $_value
			push-var $v

post-cond
	rule ??
	pre-conds 2
	pre-cond 3
		push-var $r
		word $get
		word $[
		make-multi-var $cb
		word $]
	pre-cond 3
		push-var $r
		word $_value
		make-var $v
	post-conds 2
	post-cond
		fact 6
			push-multi-var $cb
			push-var $v
	post-cond
		fact 6
			push-var $r
			word $_none

post-cond
	fact 6
		push-var $r
		word $_none

Implementation

begin
    """
    One memory is a $(2^16) long table of two bytes.
    - `data::SVector{2^16, UInt16}`: the table, a UInt16 is named a cell
    - `read_pointer::UInt16`: where are we reading in the table
    - `write_pointer::UInt16`: where are we writing in the table
    """
    @kwdef mutable struct Memory
        data::SVector{2^16, UInt16} = @SVector zeros(2^16)
        read_pointer::UInt16 = 0
        write_pointer::UInt16 = 0
    end

    """
    The Machine.
    - `facts::Memory`: the on-going processes
    - `rules::Memory`: the syncing rules
    - `bindings::Memory`: the temporay bindings when using `?x` and `\$x` in a application of the post-conditions of a query or a rule
    - `program::Memory`: the program loaded, and future bytes to execute
    """
    @kwdef mutable struct Machine
        facts::Memory # TODO: should act like a linked list to drop facts easily
        rules::Memory
        bindings::Memory
        program::Memory
    end

    
    """
    The Operation Codes.
    - `name::Symbol`: the name of the code
    - `bytecode::UInt16`: the bytes to match against
    - `params::UInt8`: the number of params it expects
    """
    struct OpCode
        name::Symbol
        bytecode::UInt16
        params::UInt8
        description::String
    end

    opcodes_by_bytecode::Dict{UInt16, OpCode} = Dict()
    
    function make_opcode(n::Symbol, b::UInt16, p::UInt8, d::String)
        o = OpCode(n, b, UInt8(p), d)
        opcodes_by_bytecode[b] = o
        return o
    end

    MK_RULE = make_opcode(:mk_rule, 0x8000, 0x01, "Make a rule: [number of cells to copy at `Machine.rules`]")
    MK_QEST = make_opcode(:mk_qest, 0x8001, 0x01, "Make a query: [number of cells to execute]")
    MK_PREC = make_opcode(:mk_prec, 0x8002, 0x01, "Make a pre-condition: [number of symbols in pre-condition to match against for accepting the pre-condition]")
    NB_PREC = make_opcode(:nb_prec, 0x8003, 0x01, "Indicate the number of pre-conditions in a rule: [number of pre-conditions]")
    MK_POST = make_opcode(:mk_post, 0x8004, 0x00, "Indicate that next is a post-condition")
    NB_POST = make_opcode(:nb_post, 0x8005, 0x01, "Indicate the number of post-condition: [number of post-conditions]")
    MK_FACT = make_opcode(:mk_fact, 0x8006, 0x01, "Make a fact: [number of cells to copy to `Machine.facts`]")
    MK_WORD = make_opcode(:mk_word, 0x8007, 0x01, "Make a word: [word identifier]")
    MK_SVAR = make_opcode(:mk_svar, 0x8008, 0x01, "Make a single symbol variable: [variable identifier in `Machine.bindings`]")
    LD_SVAR = make_opcode(:ld_svar, 0x8009, 0x01, "Load a single symbol variable: [key to `Machine.bindings`]")
    MK_MVAR = make_opcode(:mk_mvar, 0x800a, 0x01, "Make a multiple symbols variable: [variable identifier in `Machine.bindings`]")
    LD_MVAR = make_opcode(:ld_mvar, 0x800b, 0x01, "Load a multiple symbols variable: [key to `Machine.bindings`]")
    LI_UTF1 = make_opcode(:li_utf1, 0x800c, 0x01, "Make a 1 or 2 byte long char: [UTF-8 bytes]")
    LI_UTF2 = make_opcode(:li_utf2, 0x800d, 0x02, "Make a 3 or 4 byte long char: [UTF-8 bytes]")
    LI_INTG = make_opcode(:li_intg, 0x800e, 0x01, "Make an integer: [the integer]")


    md"""
    ### Memory
    $(@doc Memory)

    ### Machine
    $(@doc Machine)

    ### Operation Codes
    $(@doc OpCode)
    """
end

Memory

One memory is a 65536 long table of two bytes.

Machine

The Machine.

Operation Codes

The Operation Codes.

MK_RULE

Make a rule: [number of cells to copy at Machine.rules]

MK_QEST

Make a query: [number of cells to execute]

MK_PREC

Make a pre-condition: [number of symbols in pre-condition to match against for accepting the pre-condition]

NB_PREC

Indicate the number of pre-conditions in a rule: [number of pre-conditions]

MK_POST

Indicate that next is a post-condition

NB_POST

Indicate the number of post-condition: [number of post-conditions]

MK_FACT

Make a fact: [number of cells to copy to Machine.facts]

MK_WORD

Make a word: [word identifier]

MK_SVAR

Make a single symbol variable: [variable identifier in Machine.bindings]

LD_SVAR

Load a single symbol variable: [key to Machine.bindings]

MK_MVAR

Make a multiple symbols variable: [variable identifier in Machine.bindings]

LD_MVAR

Load a multiple symbols variable: [key to Machine.bindings]

LI_UTF1

Make a 1 or 2 byte long char: [UTF-8 bytes]

LI_UTF2

Make a 3 or 4 byte long char: [UTF-8 bytes]

LI_INTG

Make an integer: [the integer]