From 9317d71022c11cc09442033431816a95d143af50 Mon Sep 17 00:00:00 2001 From: Lucas Bajolet Date: Tue, 26 May 2015 16:36:07 -0400 Subject: [PATCH] lib/standard: Introduce Byte type in kernel Signed-off-by: Lucas Bajolet --- lib/standard/kernel.nit | 112 +++++++++++++++++++++++++++++++++ lib/standard/string.nit | 20 ++++++ lib/standard/string_nit.c | 10 +++ lib/standard/string_nit.h | 2 + src/compiler/abstract_compiler.nit | 81 ++++++++++++++++++++++++ src/compiler/separate_compiler.nit | 2 +- src/ffi/java.nit | 4 ++ src/interpreter/naive_interpreter.nit | 63 +++++++++++++++++++ src/model/model.nit | 3 + src/nitni/nitni_base.nit | 2 + src/rapid_type_analysis.nit | 1 + 11 files changed, 299 insertions(+), 1 deletion(-) diff --git a/lib/standard/kernel.nit b/lib/standard/kernel.nit index ffd684a..c596bb3 100644 --- a/lib/standard/kernel.nit +++ b/lib/standard/kernel.nit @@ -275,6 +275,12 @@ interface Numeric # assert 5.to_f != 5 # Float and Int are not equals fun to_f: Float is abstract + # The byte equivalent of `self` + # + # assert (-1).to_b == 0xFF.to_b + # assert (1.9).to_b == 1.to_b + fun to_b: Byte is abstract + # Is this the value of zero in its domain? fun is_zero: Bool do return self == zero @@ -344,6 +350,7 @@ universal Float redef fun to_i is intern redef fun to_f do return self + redef fun to_b is intern redef fun zero do return 0.0 redef fun value_of(val) do return val.to_f @@ -402,6 +409,110 @@ universal Float end end +# Native bytes. +# Same as a C `unsigned char` +universal Byte + super Discrete + super Numeric + + redef type OTHER: Byte + + redef fun successor(i) do return self + i.to_b + redef fun predecessor(i) do return self - i.to_b + + redef fun object_id is intern + redef fun hash do return self.to_i + redef fun ==(i) is intern + redef fun !=(i) is intern + redef fun output is intern + + redef fun <=(i) is intern + redef fun <(i) is intern + redef fun >=(i) is intern + redef fun >(i) is intern + redef fun +(i) is intern + + # On an Byte, unary minus will return `(256 - self) % 256` + # + # assert -(1.to_b) == 0xFF.to_b + # assert -(0.to_b) == 0x00.to_b + redef fun - is intern + redef fun -(i) is intern + redef fun *(i) is intern + redef fun /(i) is intern + + # Modulo of `self` with `i`. + # + # Finds the remainder of division of `self` by `i`. + # + # assert 5.to_b % 2.to_b == 1.to_b + # assert 10.to_b % 2.to_b == 0.to_b + fun %(i: Byte): Byte is intern + + redef fun zero do return 0.to_b + redef fun value_of(val) do return val.to_b + + # `i` bits shift fo the left (aka <<) + # + # assert 5.to_b.lshift(1) == 10.to_b + fun lshift(i: Int): Byte is intern + + # alias of `lshift` + fun <<(i: Int): Byte do return lshift(i) + + # `i` bits shift fo the right (aka >>) + # + # assert 5.to_b.rshift(1) == 2.to_b + fun rshift(i: Int): Byte is intern + + # alias of `rshift` + fun >>(i: Int): Byte do return rshift(i) + + redef fun to_i is intern + redef fun to_f is intern + redef fun to_b do return self + + redef fun distance(i) do return (self - i).to_i + + redef fun <=>(other) + do + if self < other then + return -1 + else if other < self then + return 1 + else + return 0 + end + end + + redef fun is_between(c, d) + do + if self < c or d < self then + return false + else + return true + end + end + + redef fun max(other) + do + if self < other then + return other + else + return self + end + end + + redef fun min(c) + do + if c < self then + return c + else + return self + end + end +end + # Native integer numbers. # Correspond to C int. universal Int @@ -459,6 +570,7 @@ universal Int redef fun to_i do return self redef fun to_f is intern + redef fun to_b is intern redef fun distance(i) do diff --git a/lib/standard/string.nit b/lib/standard/string.nit index ff46e46..b02ff9b 100644 --- a/lib/standard/string.nit +++ b/lib/standard/string.nit @@ -2035,6 +2035,26 @@ redef class Bool end end +redef class Byte + # C function to calculate the length of the `NativeString` to receive `self` + private fun byte_to_s_len: Int is extern "native_byte_length_str" + + # C function to convert an nit Int to a NativeString (char*) + private fun native_byte_to_s(nstr: NativeString, strlen: Int) is extern "native_byte_to_s" + + # Displayable byte in its hexadecimal form (0x..) + # + # assert 1.to_b.to_s == "0x01" + # assert (-123).to_b.to_s == "0x85" + redef fun to_s do + var nslen = byte_to_s_len + var ns = new NativeString(nslen + 1) + ns[nslen] = '\0' + native_byte_to_s(ns, nslen + 1) + return ns.to_s_with_length(nslen) + end +end + redef class Int # Wrapper of strerror C function diff --git a/lib/standard/string_nit.c b/lib/standard/string_nit.c index 686d6be..050ab95 100644 --- a/lib/standard/string_nit.c +++ b/lib/standard/string_nit.c @@ -20,3 +20,13 @@ long native_int_length_str(long recv){ void native_int_to_s(long recv, char* str, long buflen){ snprintf(str, buflen, "%ld", recv); } + +// Returns the length of `recv` as a `char*` (excluding the null character) +long native_byte_length_str(unsigned char recv){ + return snprintf(NULL, 0, "0x%02x", recv); +} + +// Byte to NativeString method +void native_byte_to_s(unsigned char recv, char* str, long buflen){ + snprintf(str, buflen, "0x%02x", recv); +} diff --git a/lib/standard/string_nit.h b/lib/standard/string_nit.h index f33580f..c1c7818 100644 --- a/lib/standard/string_nit.h +++ b/lib/standard/string_nit.h @@ -15,5 +15,7 @@ long native_int_length_str(long recv); void native_int_to_s(long recv, char* str, long buflen); +long native_byte_length_str(unsigned char recv); +void native_byte_to_s(unsigned char recv, char* str, long buflen); #endif diff --git a/src/compiler/abstract_compiler.nit b/src/compiler/abstract_compiler.nit index 8d3f7db..259c597 100644 --- a/src/compiler/abstract_compiler.nit +++ b/src/compiler/abstract_compiler.nit @@ -1455,6 +1455,14 @@ abstract class AbstractCompilerVisitor return res end + # Generate a byte value + fun byte_instance(value: Byte): RuntimeVariable + do + var t = mmodule.byte_type + var res = new RuntimeVariable("((unsigned char){value.to_s})", t, t) + return res + end + # Generate a char value fun char_instance(value: Char): RuntimeVariable do @@ -1838,6 +1846,8 @@ redef class MClassType return "char" else if mclass.name == "Float" then return "double" + else if mclass.name == "Byte" then + return "unsigned char" else if mclass.name == "NativeString" then return "char*" else if mclass.name == "NativeArray" then @@ -1868,6 +1878,8 @@ redef class MClassType return "c" else if mclass.name == "Float" then return "d" + else if mclass.name == "Byte" then + return "b" else if mclass.name == "NativeString" then return "str" else if mclass.name == "NativeArray" then @@ -2098,6 +2110,9 @@ redef class AMethPropdef else if pname == "to_f" then v.ret(v.new_expr("(double){arguments[0]}", ret.as(not null))) return true + else if pname == "to_b" then + v.ret(v.new_expr("(unsigned char){arguments[0]}", ret.as(not null))) + return true else if pname == "ascii" then v.ret(v.new_expr("{arguments[0]}", ret.as(not null))) return true @@ -2141,6 +2156,69 @@ redef class AMethPropdef v.ret(v.new_expr("(unsigned char){arguments[0]}", ret.as(not null))) return true end + else if cname == "Byte" then + if pname == "output" then + v.add("printf(\"%x\\n\", {arguments.first});") + return true + else if pname == "object_id" then + v.ret(v.new_expr("(long){arguments.first}", ret.as(not null))) + return true + else if pname == "+" then + v.ret(v.new_expr("{arguments[0]} + {arguments[1]}", ret.as(not null))) + return true + else if pname == "-" then + v.ret(v.new_expr("{arguments[0]} - {arguments[1]}", ret.as(not null))) + return true + else if pname == "unary -" then + v.ret(v.new_expr("-{arguments[0]}", ret.as(not null))) + return true + else if pname == "unary +" then + v.ret(arguments[0]) + return true + else if pname == "*" then + v.ret(v.new_expr("{arguments[0]} * {arguments[1]}", ret.as(not null))) + return true + else if pname == "/" then + v.ret(v.new_expr("{arguments[0]} / {arguments[1]}", ret.as(not null))) + return true + else if pname == "%" then + v.ret(v.new_expr("{arguments[0]} % {arguments[1]}", ret.as(not null))) + return true + else if pname == "lshift" then + v.ret(v.new_expr("{arguments[0]} << {arguments[1]}", ret.as(not null))) + return true + else if pname == "rshift" then + v.ret(v.new_expr("{arguments[0]} >> {arguments[1]}", ret.as(not null))) + return true + else if pname == "==" then + v.ret(v.equal_test(arguments[0], arguments[1])) + return true + else if pname == "!=" then + var res = v.equal_test(arguments[0], arguments[1]) + v.ret(v.new_expr("!{res}", ret.as(not null))) + return true + else if pname == "<" then + v.ret(v.new_expr("{arguments[0]} < {arguments[1]}", ret.as(not null))) + return true + else if pname == ">" then + v.ret(v.new_expr("{arguments[0]} > {arguments[1]}", ret.as(not null))) + return true + else if pname == "<=" then + v.ret(v.new_expr("{arguments[0]} <= {arguments[1]}", ret.as(not null))) + return true + else if pname == ">=" then + v.ret(v.new_expr("{arguments[0]} >= {arguments[1]}", ret.as(not null))) + return true + else if pname == "to_i" then + v.ret(v.new_expr("(long){arguments[0]}", ret.as(not null))) + return true + else if pname == "to_f" then + v.ret(v.new_expr("(double){arguments[0]}", ret.as(not null))) + return true + else if pname == "ascii" then + v.ret(v.new_expr("{arguments[0]}", ret.as(not null))) + return true + end else if cname == "Bool" then if pname == "output" then v.add("printf({arguments.first}?\"true\\n\":\"false\\n\");") @@ -2209,6 +2287,9 @@ redef class AMethPropdef else if pname == "to_i" then v.ret(v.new_expr("(long){arguments[0]}", ret.as(not null))) return true + else if pname == "to_b" then + v.ret(v.new_expr("(unsigned char){arguments[0]}", ret.as(not null))) + return true end else if cname == "NativeString" then if pname == "[]" then diff --git a/src/compiler/separate_compiler.nit b/src/compiler/separate_compiler.nit index 7231bbb..31a4f20 100644 --- a/src/compiler/separate_compiler.nit +++ b/src/compiler/separate_compiler.nit @@ -252,7 +252,7 @@ class SeparateCompiler do # Collect all bas box class # FIXME: this is not completely fine with a separate compilation scheme - for classname in ["Int", "Bool", "Char", "Float", "NativeString", "Pointer"] do + for classname in ["Int", "Bool", "Byte", "Char", "Float", "NativeString", "Pointer"] do var classes = self.mainmodule.model.get_mclasses_by_name(classname) if classes == null then continue assert classes.length == 1 else print classes.join(", ") diff --git a/src/ffi/java.nit b/src/ffi/java.nit index 41c9c26..3f2a21e 100644 --- a/src/ffi/java.nit +++ b/src/ffi/java.nit @@ -483,6 +483,7 @@ redef class MClassType if mclass.name == "Char" then return "char" if mclass.name == "Int" then return "long" if mclass.name == "Float" then return "double" + if mclass.name == "Byte" then return "byte" return super end @@ -494,6 +495,7 @@ redef class MClassType if mclass.name == "Char" then return "jchar" if mclass.name == "Int" then return "jlong" if mclass.name == "Float" then return "jdouble" + if mclass.name == "Byte" then return "jbyte" return super end @@ -553,6 +555,7 @@ redef class MClassType if mclass.name == "Char" then return "C" if mclass.name == "Int" then return "J" if mclass.name == "Float" then return "D" + if mclass.name == "Byte" then return "B" return super end @@ -565,6 +568,7 @@ redef class MClassType if mclass.name == "Char" then return "Char" if mclass.name == "Int" then return "Long" if mclass.name == "Float" then return "Double" + if mclass.name == "Byte" then return "Byte" return super end end diff --git a/src/interpreter/naive_interpreter.nit b/src/interpreter/naive_interpreter.nit index 9708f3f..3626d33 100644 --- a/src/interpreter/naive_interpreter.nit +++ b/src/interpreter/naive_interpreter.nit @@ -207,6 +207,15 @@ class NaiveInterpreter return instance end + # Return the byte instance associated with `val`. + fun byte_instance(val: Byte): Instance + do + var t = mainmodule.byte_type + var instance = new PrimitiveInstance[Byte](t, val) + init_instance_primitive(instance) + return instance + end + # Return the char instance associated with `val`. fun char_instance(val: Char): Instance do @@ -632,6 +641,10 @@ abstract class Instance # else aborts fun to_f: Float do abort + # Return the integer value if the instance is a byte. + # else aborts + fun to_b: Byte do abort + # The real value encapsulated if the instance is primitive. # Else aborts. fun val: nullable Object do abort @@ -677,6 +690,8 @@ class PrimitiveInstance[E] redef fun to_i do return val.as(Int) redef fun to_f do return val.as(Float) + + redef fun to_b do return val.as(Byte) end # Information about local variables in a running method @@ -867,6 +882,8 @@ redef class AMethPropdef return v.char_instance(args[0].to_i.ascii) else if pname == "to_f" then return v.float_instance(args[0].to_i.to_f) + else if pname == "to_b" then + return v.byte_instance(args[0].to_i.to_b) else if pname == "lshift" then return v.int_instance(args[0].to_i.lshift(args[1].to_i)) else if pname == "rshift" then @@ -894,6 +911,50 @@ redef class AMethPropdef else if pname == "strerror_ext" then return v.native_string_instance(recvval.strerror) end + else if cname == "Byte" then + var recvval = args[0].to_b + if pname == "unary -" then + return v.byte_instance(-args[0].to_b) + else if pname == "unary +" then + return args[0] + else if pname == "+" then + return v.byte_instance(args[0].to_b + args[1].to_b) + else if pname == "-" then + return v.byte_instance(args[0].to_b - args[1].to_b) + else if pname == "*" then + return v.byte_instance(args[0].to_b * args[1].to_b) + else if pname == "%" then + return v.byte_instance(args[0].to_b % args[1].to_b) + else if pname == "/" then + return v.byte_instance(args[0].to_b / args[1].to_b) + else if pname == "<" then + return v.bool_instance(args[0].to_b < args[1].to_b) + else if pname == ">" then + return v.bool_instance(args[0].to_b > args[1].to_b) + else if pname == "<=" then + return v.bool_instance(args[0].to_b <= args[1].to_b) + else if pname == ">=" then + return v.bool_instance(args[0].to_b >= args[1].to_b) + else if pname == "<=>" then + return v.int_instance(args[0].to_b <=> args[1].to_b) + else if pname == "to_f" then + return v.float_instance(args[0].to_b.to_f) + else if pname == "to_i" then + return v.int_instance(args[0].to_b.to_i) + else if pname == "lshift" then + return v.byte_instance(args[0].to_b.lshift(args[1].to_i)) + else if pname == "rshift" then + return v.byte_instance(args[0].to_b.rshift(args[1].to_i)) + else if pname == "byte_to_s_len" then + return v.int_instance(recvval.to_s.length) + else if pname == "native_byte_to_s" then + var s = recvval.to_s + var srecv = args[1].val.as(Buffer) + srecv.clear + srecv.append(s) + srecv.add('\0') + return null + end else if cname == "Char" then var recv = args[0].val.as(Char) if pname == "ascii" then @@ -937,6 +998,8 @@ redef class AMethPropdef return v.bool_instance(recv >= args[1].to_f) else if pname == "to_i" then return v.int_instance(recv.to_i) + else if pname == "to_b" then + return v.byte_instance(recv.to_b) else if pname == "cos" then return v.float_instance(args[0].to_f.cos) else if pname == "sin" then diff --git a/src/model/model.nit b/src/model/model.nit index 94f11f2..908cb60 100644 --- a/src/model/model.nit +++ b/src/model/model.nit @@ -206,6 +206,9 @@ redef class MModule # The primitive type `Int` var int_type: MClassType = self.get_primitive_class("Int").mclass_type is lazy + # The primitive type `Byte` + var byte_type: MClassType = self.get_primitive_class("Byte").mclass_type is lazy + # The primitive type `Char` var char_type: MClassType = self.get_primitive_class("Char").mclass_type is lazy diff --git a/src/nitni/nitni_base.nit b/src/nitni/nitni_base.nit index a1f49a7..7cf6bbc 100644 --- a/src/nitni/nitni_base.nit +++ b/src/nitni/nitni_base.nit @@ -92,6 +92,7 @@ redef class MClassType if name == "Char" then return "char" if name == "Float" then return "double" if name == "Int" then return "long" + if name == "Byte" then return "unsigned char" if name == "NativeString" then return "char*" if mclass.kind == extern_kind then var ctype = mclass.ctype @@ -107,6 +108,7 @@ redef class MClassType if name == "Char" then return "char" if name == "Float" then return "double" if name == "Int" then return "long" + if name == "Byte" then return "unsigned char" if name == "NativeString" then return "char*" if mclass.kind == extern_kind then return "void*" return "struct nitni_instance *" diff --git a/src/rapid_type_analysis.nit b/src/rapid_type_analysis.nit index 8e5565c..bcd9f8e 100644 --- a/src/rapid_type_analysis.nit +++ b/src/rapid_type_analysis.nit @@ -213,6 +213,7 @@ class RapidTypeAnalysis force_alive("Float") force_alive("Char") force_alive("Pointer") + force_alive("Byte") while not todo.is_empty do var mmethoddef = todo.shift -- 1.7.9.5