view modules/bytearray.tp @ 331:61f5b794d939

Breaking change: method call syntax now always uses the syntactic receiver as the actual receiver. This makes its behavior different from function call syntax, but solves some problems with methods being shadowed by local variables and the like.
author Michael Pavone <pavone@retrodev.com>
date Sat, 28 Mar 2015 14:21:04 -0700
parents 4c669942c30d
children ff7ea11b4b60
line wrap: on
line source

#{
	includeSystemHeader: "unistd.h"
	includeSystemHeader: "sys/mman.h"
	
	fromOpaque:withSize <- :opaque :size{
		#{
			llProperty: bytes withType: uint32_t
			llProperty: buffer withType: (void ptr)
			llMessage: _init_buf withVars: {
				sz <- obj_int32 ptr
				opaque <- cpointer ptr
			} andCode: :opaque sz {
				bytes <- sz num
				buffer <- (opaque val)
				self
			}

			llMessage: _buf_ptr withVars: {
				ptrret <- cpointer ptr
			} andCode: {
				ptrret <- make_object: (addr_of: cpointer_meta) NULL 0
				ptrret val!: buffer
				ptrret
			}

			llMessage: length withVars: {
				intret <- obj_int32 ptr
			} andCode: {
				intret <- make_object: (addr_of: obj_int32_meta) NULL 0
				intret num!: bytes
				intret
			}

			llMessage: set withVars: {
				offset <- obj_int32 ptr
				newval <- obj_uint8 ptr
			} andCode: :offset newval {
				(buffer castTo: (uint8_t ptr)) set: (offset num) (newval num)
				self
			}
			llMessage: get withVars: {
				offset <- obj_int32 ptr
				ret <- obj_uint8 ptr
			} andCode: :offset {
				ret <- make_object: (addr_of: obj_uint8_meta) NULL 0
				ret num!: ((buffer castTo: (uint8_t ptr)) get: (offset num))
				ret
			}

			llMessage: shrinkTo withVars: {
				newsize <- obj_int32 ptr
			} andCode: :newsize {
				if: (newsize num) < bytes {
					bytes <- newsize num
				}
				self
			}

			llMessage: stringFrom:to withVars: {
				from <- obj_int32 ptr
				to <- obj_int32 ptr
				str <- string ptr
			} andCode: :from :to {
				//probably should do some UTF-8 validation at some point
				str <- make_object: (addr_of: string_meta) NULL 0
				str bytes!: (to num) - (from num)
				str len!: (str bytes)
				str data!: (GC_MALLOC_ATOMIC: (str bytes) + 1)
				memcpy: (str data) (buffer castTo: (uint8_t ptr)) + (from num) (str bytes)
				(str data) set: (str bytes) 0
				str
			}

			string <- {
				stringFrom: 0 to: length
			}

			findChar:from:else <- :char :start found :else {
				notfound <- true
				n <- length
				i <- start
				while: { notfound && i < n } do: {
					if: (get: i) = char {
						notfound <- false
					} else: {
						i <- i + 1
					}
				}
				if: notfound else else: {
					found: i
				}
			}
		} _init_buf: opaque size
	}

	normal <- :size {
		helper <- #{
			llMessage: alloc withVars: {
				size <- obj_int32 ptr
				opaqueret <- cpointer ptr
			} andCode: :size {
				opaqueret <- make_object: (addr_of: cpointer_meta) NULL 0
				opaqueret val!: (GC_MALLOC_ATOMIC: (size num))
				opaqueret
			}
		}
		fromOpaque: (helper alloc: size) withSize: size
	}

	executable <- :size {
		buf <- #{
			llProperty: bytes withType: uint32_t
			llProperty: buffer withType: (void ptr)
			llMessage: _init withVars: {
				sz <- obj_int32 ptr
			} andCode: :sz {
				bytes <- sz num
				buffer <- sbrk: bytes
				mprotect: buffer bytes (PROT_READ or PROT_WRITE or PROT_EXEC)
				self
			}
			llMessage: set withVars: {
				offset <- obj_int32 ptr
				newval <- obj_uint8 ptr
			} andCode: :offset newval {
				(buffer castTo: (uint8_t ptr)) set: (offset num) (newval num)
				self
			}
			llMessage: get withVars: {
				offset <- obj_int32 ptr
				ret <- obj_uint8 ptr
			} andCode: :offset {
				ret <- make_object: (addr_of: obj_uint8_meta) NULL 0
				ret num!: ((buffer castTo: (uint8_t ptr)) get: (offset num))
				ret
			}
			llMessage: run withVars: {
				fun <- uint64_t funptr
				funret <- obj_uint64 ptr
			} andCode: {
				funret <- make_object: (addr_of: obj_uint64_meta) NULL 0
				fun <- buffer
				funret num!: ( fun: )
				funret
			}

			llMessage: runWithArg withVars: {
				fun <- uint64_t funptr: uint64_t
				funret <- obj_uint64 ptr
				arg <- obj_uint64 ptr
			} andCode: :arg {
				fun <- buffer
				funret <- make_object: (addr_of: obj_uint64_meta) NULL 0
				funret num!: ( fun: (arg num) )
				funret
			}
		}
		buf _init: size
	}

	executableFromBytes <- :bytes {
		totalSize <- bytes fold: 0 with: :acc el {
			acc + (el length)
		}
		ba <- executable: totalSize
		bytes fold: 0 with: :idx el {
			el flattenTo: ba at: idx
		}
		ba
	}
}