xeh
What is XEH?
XEH is a dynamic, stack-oriented scripting language designed for live coding as well as a tool for binary data parsing and construction.
What make XEH interestig is ability to save snapshot, test something and rollback without restarting the whole program, just like a video game!
Building and Running
cargo build --release
# command line options
xeh [options] [sources]
Options:
-i path input binary file
-e expression evaluate expression
-r enable reverse debugging
-h, --help print help
# repl commands
/trial switch to live coding mode
/repl switch to REPL mode
/snapshot snapshot program state
/rollback rollback to the latest snapshot
/next debugger - step forward
/rnext debugger - step backward
Quick Language Reference
Comments
\ singleline comment
\(
multiline commet
\)
Literals
\ decimal
7 -99 1_000
\ hex
0xff 0x11_EE
\ binary
0b11111 0b1111_1111
\ real
2.78 -1.2e-5
\ string
"escapes \\ \" \r \n \t"
Words
The whole program constist of words and literals. Depending on the definition word maybe function, variable or just an identifier.
- Words are separated by whitespaces.
- Word name consist of any characters, but can't start with digit or double quote.
\ valid words
abc
my-name
+[]
_"d^%$$$#112d'"d+"
a0000-/-(22)
.99
\ invalid words
0waa
9sss
"abc
Functions
Function definition stats with word, then function name and body follow,
definition ends with .
: hello "Hello!" println ;
Variable
Variable definition starts with then name follow, initial value is taken from the stack.
\ define a new global variable
0 var counter
\ update counter
10 -> counter
Locals
Local is a read-only binding visible only inside the function body. Initial value is taken from the stack.
\ locals
: print2
local b
local a
"a = " print a println
"b = " print b println
;
1 2 print2
Conditional execution
Y 0 <= if
Y abs -> Y
endif
X 2 mod zero? if "even" else "odd" endif
\ select one case of the multiple different choices
X case
0 of "A" endof
1 of "B" endof
\ fallback, drop unmatched value from the stack
drop
"Other"
endcase
Basic loops
\ loop with pre-codnition, test condition before every iteration
begin remain 5 > while
read-more
repeat
\ post condition, restart loop if condition is false
begin read-byte zero? until
\ endless loop
begin
day-of-week "friday" == if
\ break loop execution
break
then
repeat
Counted loops
\ count from 0 to 10, current loop index is accessed with "I"
10 0 do I print loop
\ outer loop index is accessed with J
10 5 do \ J
5 0 do \ I
"J=" print J print
"I=" print I print
loop
newline
loop
Foreach loop
\ put next item on top of the stack, item index is "I"
[ 1 2 ] foreach
\ current item
println
\ current index
I println
loop
\ Put every key and value on top of the stack
{ 1 2 } foreach
println \ key
println \ value
loop
\ Chars
"abc" foreach println loop
\ Bits
|f0| foreach println loop
Tags
Tags is a custom property map sticked to the value but not directly accessible. Tags have no impact on using value and dissapear after value modification.
\ stick "abc" string to the integer 10
10 ^{ "ten" "name" ^} var X
\ get "color" property
X "color" get-tag println
\ add color tag
X "red" "color" insert-tag -> X
\ show all tags
X tags println
X 1 + println
Meta evaluation and compilation
Source code execution operate in three modes:
* Compilation - source code translation to the virtual machine bytecode
* Evaluation - execution of the generated bytecode
* Meta evaluation - using the result of the source code execution as input for compilation
User is free to switch forth and back between the modes.
When the compiler see the it switch to the meta mode, then execute code till the closing .
All values on the stack are passed to the parent mode.
: fib dup 1 > if
dup 2 - fib
swap 1 - fib
+
endif
;
\ compute Fibonacci number at compile-time
(# 20 fib #) var fib-of-20
Constants
Constant is a read-only word that inline its value immediately without refering to the memory cell. Initial value is taken from the stack and must be defined inside of the meta mode.
#( 1.0 60.0 / const FRAME-TIME #)
Enums
Create enumerated list of constants.
enum MyEnum
\ By default enumeration starts with zero.
: A
: B
\ Use `=` to assign custom value to the field
B 2 + = C
endenum
Destructuring
let PATTERN
Ensure that each name in the PATTERN have corresponding value. Using literal instead of the name test that value is exactly match, otherwise error is raised.
\ bind 1 to a
1 let a
\ test that a is 1
a let 1
\ raise error, when a not equal to 2
a let 2
\ bind vector elements
[ [ 1 2 ] [ 3 4 ] ] let [ [ a b ] [ c d ] ]
\ slice first two elements of the vector and bind remaining to the xs
[ 1 2 3 5 7 ] let [ x1 x2 & xs ]
\ find map keys
{ 1 "key1" [ 2 3 ] "key2" } let { "key1" x "key2" [ 2 y ] }
\ split the value and tags
123 ^{ "red" "color" ^} let ^ all-tags val
\ find tag property
123 ^{ 1 "a" 2 "b" ^} let ^ { "a" aval } val
Source code injection
Meta evaluation result might serve as input for compilation. When compiler see immediate word instead of the closing bracket, first compiler join result into a string and then treat that string as a part of the source code.
\ define variables from list
#( [ "aa" "bb" "cc" ] foreach I " var " rot loop ~)
bb println