Started working on basic wasm encoding/serialization. Added binary_file_writing, generalized arity comparison operators, bitwise operators, parsing of hex numbers, and wasm w/ memory section deserialization

This commit is contained in:
Nathan Braswell
2021-04-19 01:39:04 -04:00
parent ed3b2ce743
commit e1fd8abd4f
5 changed files with 177 additions and 26 deletions

11
comp_wasm.kp Normal file
View File

@@ -0,0 +1,11 @@
(with_import "./wasm.kp"
(let (
_ (println "args" *ARGV*)
(_ _ in out) (cond (!= (len *ARGV*) 4) (error "wrong number of params")
true *ARGV*)
_ (println "in" in "out" out)
wasm_code [
]
_ (write_file out (wasm_to_binary wasm_code))
return_code 0
) return_code ))

View File

@@ -716,7 +716,7 @@ fun main(argc: int, argv: **char): int {
}
return KPResult::Ok(kpString(to_ret));
})), kpNil(), ret_0_sym)
grammar.add_to_nonterminal(atom, vec(grammar.add_terminal("-|(([a-z]|[A-Z]|_|\\*|/|\\?|\\+|!|=|&|<|>|%)([a-z]|[A-Z]|_|[0-9]|\\*|\\?|\\+|-|!|=|&|<|>|%)*)", kpNil(), fun(_: ref KPValue, input: ref str, l: int, r: int): KPResult {
grammar.add_to_nonterminal(atom, vec(grammar.add_terminal("-|(([a-z]|[A-Z]|_|\\*|/|\\?|\\+|!|=|&|\\||<|>|%)([a-z]|[A-Z]|_|[0-9]|\\*|\\?|\\+|-|!|=|&|\\||<|>|%)*)", kpNil(), fun(_: ref KPValue, input: ref str, l: int, r: int): KPResult {
var s = input.slice(l,r)
if s == "true" {
return KPResult::Ok(kpTrue());
@@ -1005,6 +1005,39 @@ fun main(argc: int, argv: **char): int {
return make_pair(null<KPEnv>(), KPResult::Ok(kpInt(to_ret)))
}));
env->set(str("&"), make_builtin_combiner(str("&"), 1, false, fun(params: vec<KPValue>, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> {
if params.size != 2 {
return make_pair(null<KPEnv>(), KPResult::Err(kpString(str("Need 2 params to &"))))
}
if !params[0].is_int() { return make_pair(null<KPEnv>(), KPResult::Err(kpString(str("called & with first not an int")))); }
if !params[1].is_int() { return make_pair(null<KPEnv>(), KPResult::Err(kpString(str("called & with second not an int")))); }
return make_pair(null<KPEnv>(), KPResult::Ok(kpInt(params[0].get_int() & params[1].get_int())))
}));
env->set(str("|"), make_builtin_combiner(str("|"), 1, false, fun(params: vec<KPValue>, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> {
if params.size != 2 {
return make_pair(null<KPEnv>(), KPResult::Err(kpString(str("Need 2 params to |"))))
}
if !params[0].is_int() { return make_pair(null<KPEnv>(), KPResult::Err(kpString(str("called | with first not an int")))); }
if !params[1].is_int() { return make_pair(null<KPEnv>(), KPResult::Err(kpString(str("called | with second not an int")))); }
return make_pair(null<KPEnv>(), KPResult::Ok(kpInt(params[0].get_int() | params[1].get_int())))
}));
env->set(str("<<"), make_builtin_combiner(str("<<"), 1, false, fun(params: vec<KPValue>, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> {
if params.size != 2 {
return make_pair(null<KPEnv>(), KPResult::Err(kpString(str("Need 2 params to <<"))))
}
if !params[0].is_int() { return make_pair(null<KPEnv>(), KPResult::Err(kpString(str("called << with first not an int")))); }
if !params[1].is_int() { return make_pair(null<KPEnv>(), KPResult::Err(kpString(str("called << with second not an int")))); }
return make_pair(null<KPEnv>(), KPResult::Ok(kpInt(params[0].get_int() << params[1].get_int())))
}));
env->set(str(">>"), make_builtin_combiner(str(">>"), 1, false, fun(params: vec<KPValue>, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> {
if params.size != 2 {
return make_pair(null<KPEnv>(), KPResult::Err(kpString(str("Need 2 params to >>"))))
}
if !params[0].is_int() { return make_pair(null<KPEnv>(), KPResult::Err(kpString(str("called >> with first not an int")))); }
if !params[1].is_int() { return make_pair(null<KPEnv>(), KPResult::Err(kpString(str("called >> with second not an int")))); }
return make_pair(null<KPEnv>(), KPResult::Ok(kpInt(params[0].get_int() >> params[1].get_int())))
}));
env->set(str("="), make_builtin_combiner(str("="), 1, false, fun(params: vec<KPValue>, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> {
if params.size != 2 {
return make_pair(null<KPEnv>(), KPResult::Err(kpString(str("Need 2 params to ="))))
@@ -1018,36 +1051,56 @@ fun main(argc: int, argv: **char): int {
return make_pair(null<KPEnv>(), KPResult::Ok(kpBool(!params[0].equals(params[1]))))
}));
env->set(str("<"), make_builtin_combiner(str("<"), 1, false, fun(params: vec<KPValue>, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> {
if params.size != 2 {
return make_pair(null<KPEnv>(), KPResult::Err(kpString(str("Need 2 params to <"))))
if params.size <= 1 {
return make_pair(null<KPEnv>(), KPResult::Err(kpString(str("Need 2 or more params to <"))))
}
if !params[0].is_int() { return make_pair(null<KPEnv>(), KPResult::Err(kpString(str("called < with first not an int")))); }
if !params[1].is_int() { return make_pair(null<KPEnv>(), KPResult::Err(kpString(str("called < with second not an int")))); }
return make_pair(null<KPEnv>(), KPResult::Ok(kpBool(params[0].get_int() < params[1].get_int())))
for (var i = 0; i < params.size - 1; i++;) {
if !params[i+1].is_int() { return make_pair(null<KPEnv>(), KPResult::Err(kpString(str("called < with not an int")))); }
if !(params[i].get_int() < params[i+1].get_int()) {
return make_pair(null<KPEnv>(), KPResult::Ok(kpBool(false)))
}
}
return make_pair(null<KPEnv>(), KPResult::Ok(kpBool(true)))
}));
env->set(str("<="), make_builtin_combiner(str("<="), 1, false, fun(params: vec<KPValue>, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> {
if params.size != 2 {
return make_pair(null<KPEnv>(), KPResult::Err(kpString(str("Need 2 params to <="))))
if params.size <= 1 {
return make_pair(null<KPEnv>(), KPResult::Err(kpString(str("Need 2 or more params to <="))))
}
if !params[0].is_int() { return make_pair(null<KPEnv>(), KPResult::Err(kpString(str("called <= with first not an int")))); }
if !params[1].is_int() { return make_pair(null<KPEnv>(), KPResult::Err(kpString(str("called <= with second not an int")))); }
return make_pair(null<KPEnv>(), KPResult::Ok(kpBool(params[0].get_int() <= params[1].get_int())))
for (var i = 0; i < params.size - 1; i++;) {
if !params[i+1].is_int() { return make_pair(null<KPEnv>(), KPResult::Err(kpString(str("called <= with not an int")))); }
if !(params[i].get_int() <= params[i+1].get_int()) {
return make_pair(null<KPEnv>(), KPResult::Ok(kpBool(false)))
}
}
return make_pair(null<KPEnv>(), KPResult::Ok(kpBool(true)))
}));
env->set(str(">"), make_builtin_combiner(str(">"), 1, false, fun(params: vec<KPValue>, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> {
if params.size != 2 {
return make_pair(null<KPEnv>(), KPResult::Err(kpString(str("Need 2 params to >"))))
if params.size <= 1 {
return make_pair(null<KPEnv>(), KPResult::Err(kpString(str("Need 2 or more params to >"))))
}
if !params[0].is_int() { return make_pair(null<KPEnv>(), KPResult::Err(kpString(str("called > with first not an int")))); }
if !params[1].is_int() { return make_pair(null<KPEnv>(), KPResult::Err(kpString(str("called > with second not an int")))); }
return make_pair(null<KPEnv>(), KPResult::Ok(kpBool(params[0].get_int() > params[1].get_int())))
for (var i = 0; i < params.size - 1; i++;) {
if !params[i+1].is_int() { return make_pair(null<KPEnv>(), KPResult::Err(kpString(str("called > with not an int")))); }
if !(params[i].get_int() > params[i+1].get_int()) {
return make_pair(null<KPEnv>(), KPResult::Ok(kpBool(false)))
}
}
return make_pair(null<KPEnv>(), KPResult::Ok(kpBool(true)))
}));
env->set(str(">="), make_builtin_combiner(str(">="), 1, false, fun(params: vec<KPValue>, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> {
if params.size != 2 {
return make_pair(null<KPEnv>(), KPResult::Err(kpString(str("Need 2 params to >="))))
if params.size <= 1 {
return make_pair(null<KPEnv>(), KPResult::Err(kpString(str("Need 2 or more params to >="))))
}
if !params[0].is_int() { return make_pair(null<KPEnv>(), KPResult::Err(kpString(str("called >= with first not an int")))); }
if !params[1].is_int() { return make_pair(null<KPEnv>(), KPResult::Err(kpString(str("called >= with second not an int")))); }
return make_pair(null<KPEnv>(), KPResult::Ok(kpBool(params[0].get_int() >= params[1].get_int())))
for (var i = 0; i < params.size - 1; i++;) {
if !params[i+1].is_int() { return make_pair(null<KPEnv>(), KPResult::Err(kpString(str("called >= with not an int")))); }
if !(params[i].get_int() >= params[i+1].get_int()) {
return make_pair(null<KPEnv>(), KPResult::Ok(kpBool(false)))
}
}
return make_pair(null<KPEnv>(), KPResult::Ok(kpBool(true)))
}));
env->set(str("and"), make_builtin_combiner(str("and"), 0, false, fun(params: vec<KPValue>, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> {
@@ -1319,6 +1372,36 @@ fun main(argc: int, argv: **char): int {
return make_pair(null<KPEnv>(), KPResult::Ok(kpString(get_line(params[0].get_string(), 1024))))
}
}));
env->set(str("write_file"), make_builtin_combiner(str("write_file"), 1, false, fun(params: vec<KPValue>, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> {
if params.size != 2 {
return make_pair(null<KPEnv>(), KPResult::Err(kpString(str("write_file with not a two params"))))
} else {
if !params[0].is_string() {
return make_pair(null<KPEnv>(), KPResult::Err(kpString(str("write_file with first param not a (path) string"))))
}
if params[1].is_string() {
write_file(params[0].get_string(), params[1].get_string())
} else if params[1].is_array() {
var arc = params[1].get_array_rc()
var size = arc.get().size
var out_vec = vec<char>()
for (var i = 0; i < size; i++;) {
if !arc.get()[i].is_int() {
return make_pair(null<KPEnv>(), KPResult::Err(kpString(str("write_file with vec member ") + i + "(" + pr_str(arc.get()[i], true) + ") isn't int")))
}
var int_out = arc.get()[i].get_int()
if int_out < 0 || int_out > 255 {
return make_pair(null<KPEnv>(), KPResult::Err(kpString(str("write_file with vec member ") + i + "(" + int_out + ") is out of 0-255 byte range " + int_out)))
}
out_vec.add((int_out) cast char)
}
write_file_binary(params[0].get_string(), out_vec)
} else {
return make_pair(null<KPEnv>(), KPResult::Err(kpString(str("write_file with second param not a string or array"))))
}
return make_pair(null<KPEnv>(), KPResult::Ok(kpNil()))
}
}));
env->set(str("empty_env"), kpEnv(new<KPEnv>()->construct()))
// Launch into new kraken for interface and self-hosting features

View File

@@ -138,16 +138,27 @@
string-to-int (lambda (s) (let (
helper (rec-lambda recurse (s i result)
c0 (idx "0" 0)
c9 (idx "9" 0)
ca (idx "a" 0)
cz (idx "z" 0)
cA (idx "A" 0)
cZ (idx "Z" 0)
helper (rec-lambda recurse (s i radix result)
(if (< i (len s))
(recurse s (+ i 1) (+ (* 10 result) (- (idx s i) (idx "0" 0))))
(let (c (idx s i))
(cond (<= c0 c c9) (recurse s (+ i 1) radix (+ (* radix result) (- (idx s i) c0)))
(<= ca c cz) (recurse s (+ i 1) radix (+ (* radix result) (+ 10 (- (idx s i) ca))))
(<= cA c cZ) (recurse s (+ i 1) radix (+ (* radix result) (+ 10 (- (idx s i) cA))))
true (error "Impossible char in string-to-int"))
)
result
)
))
(if (= (idx s 0) (idx "-" 0))
(- (helper s 1 0))
(helper s 0 0)
)))
(cond (= (idx s 0) (idx "-" 0)) (- (helper s 1 10 0))
(and (> (len s) 2) (or (= "0x" (slice s 0 2)) (= "0X" (slice s 0 2)))) (helper s 2 16 0)
true (helper s 0 10 0))
))
unescape-str (lambda (s) (let (
helper (rec-lambda recurse (s i r)
@@ -168,10 +179,10 @@
(array (quote WS) (array "( | |
|(;[ -~]*
))+") (lambda (x) nil))
(array (quote number) (array "-?[0-9]+") (lambda (x) (string-to-int x)))
(array (quote number) (array "(0(x|X)([0-9]|[a-f]|[A-F])+)|(-?[0-9]+)") (lambda (x) (string-to-int x)))
(array (quote string) (array "\"([#-[]| |[]-~]|(\\\\\\\\)|(\\\\n)|(\\\\t)|(\\*)|(\\\\0)|
|[ -!]|(\\\\\"))*\"") (lambda (x) (unescape-str x)))
(array (quote bool_nil_symbol) (array "-|(([a-z]|[A-Z]|_|\\*|/|\\?|\\+|!|=|&|<|>|%)([a-z]|[A-Z]|_|[0-9]|\\*|\\?|\\+|-|!|=|&|<|>|%)*)") (lambda (x) (cond (= "true" x) true
(array (quote bool_nil_symbol) (array "-|(([a-z]|[A-Z]|_|\\*|/|\\?|\\+|!|=|&|\\||<|>|%)([a-z]|[A-Z]|_|[0-9]|\\*|\\?|\\+|-|!|=|&|\\||<|>|%)*)") (lambda (x) (cond (= "true" x) true
(= "false" x) false
(= "nil" x) nil
true (str-to-symbol x))))

View File

@@ -125,7 +125,7 @@ fun write_file_binary(path: str::str, vdata: vec::vec<char>) {
defer delete(char_path)
var data = vdata.getBackingMemory()
var size = vdata.size
var fp = fopen(char_path, "w")
var fp = fopen(char_path, "wb")
fwrite((data) cast *void, (1) cast ulong, (size) cast ulong, fp)
fclose(fp)
}

46
wasm.kp Normal file
View File

@@ -0,0 +1,46 @@
(let (
; Vectors and Values
; Bytes encode themselves
encode_u_LEB128 (rec-lambda recurse (x)
(cond (< x 0x80) [x]
true (cons (| (& x 0x7F) 0x1) (recurse (>> x 8))))
)
encode_s8_LEB128 (lambda (x) (encode_u_LEB128 (& x 255)))
encode_vector (lambda (enc v)
(concat (encode_u_LEB128 (len v)) (flat_map enc v) )
)
encode_floating_point (lambda (x) (error "unimplemented"))
encode_name (lambda (name)
(encode_vector (lambda (x) [x]) name)
)
; Types
; TODO
encode_limits (lambda (x)
(cond (= 1 (len x)) (concat [0x00] (encode_u_LEB128 (idx x 0)))
(= 2 (len x)) (concat [0x01] (encode_u_LEB128 (idx x 0)) (encode_u_LEB128 (idx x 1)))
true (error "trying to encode bad limits"))
)
; Instructions
; TODO
; Modules
encode_memory_section (lambda (x)
(let (
encoded (encode_vector encode_limits x)
) (concat [0x05] (encode_u_LEB128 (len encoded)) encoded ))
)
wasm_to_binary (lambda (wasm_code)
(let (
magic [ 0x00 0x61 0x73 0x6D ]
version [ 0x01 0x00 0x00 0x00 ]
memory (encode_memory_section [ [0x20 0x30] ])
) (concat magic version memory))
)
)
(provide wasm_to_binary)
)