From: Jean Privat Date: Wed, 16 Sep 2015 17:11:50 +0000 (-0400) Subject: Merge: android/audio: fix multiple music playing when pausing app X-Git-Tag: v0.7.8~17 X-Git-Url: http://nitlanguage.org?hp=a62420d1b74402151891d2e5f3c25d71a96df7ad Merge: android/audio: fix multiple music playing when pausing app Asked by @privat because friendz's app played multiple musics when pausing/resuming the app Pull-Request: #1721 Reviewed-by: Jean Privat Reviewed-by: Alexis Laferrière Reviewed-by: Lucas Bajolet --- diff --git a/contrib/friendz/src/friendz.nit b/contrib/friendz/src/friendz.nit index 9425abe..c0554fe 100644 --- a/contrib/friendz/src/friendz.nit +++ b/contrib/friendz/src/friendz.nit @@ -19,7 +19,6 @@ import realtime import solver import mnit::tileset import app::data_store -import md5 intrude import grid intrude import level @@ -217,11 +216,11 @@ class LevelButton self.over = self.level.fullname if self.level.get_state >= l.l_won then - if game.levels[9].get_state >= l.l_won then self.over += " --- {self.level.score}/{self.level.par}" + if game.levels[9].get_state >= l.l_won then self.over += " --- {self.level.score}/{self.level.gold}" else if self.level.get_state >= l.l_open then - if game.levels[9].get_state >= l.l_open then self.over += " --- ?/{self.level.par}" + if game.levels[9].get_state >= l.l_open then self.over += " --- ?/{self.level.gold}" end - #self.enabled = l.get_state >= l.l_open + self.enabled = l.get_state >= l.l_open or game.cheated end redef fun draw(ctx) @@ -242,7 +241,7 @@ class LevelButton end ctx.blit(game.img[ix,iy], self.x, self.y) - if s == l.l_par then + if s == l.l_gold then ctx.blit(game.img2[7,0], self.x + bw*5/8, self.y-bh*1/8) end ctx.textx(self.level.name, self.x+5, self.y+5, 24, null, null) @@ -730,9 +729,9 @@ class Score end if game.levels[9].get_state >= level.l_won then if level.is_challenge then - ctx.textx("GOAL: {level.par}",self.x,self.y+44,21,"yellow",null) + ctx.textx("GOAL: {level.gold}",self.x,self.y+44,21,"yellow",null) else - ctx.textx("PAR: {level.par}",self.x,self.y+44,21,"yellow",null) + ctx.textx("GOLD: {level.gold}",self.x,self.y+44,21,"yellow",null) end end end @@ -777,7 +776,7 @@ class StatusBar do print "***STATUS** {txt}" self.tmp_txt = txt - self.tmp_txt_ttl = 20 + self.tmp_txt_ttl = 60 self.tmp_txt_color = color end @@ -873,26 +872,6 @@ redef class Game # Font var font = new TileSetFont(app.load_image("deltaforce_font.png"), 16, 17, "ABCDEFGHIJKLMNOPQRSTUVWXYZ 0123456789.:;!?\"'() -,/") - var xxx = """ - fun save_cookie(name, val:String) do - var days = 365 - var date = new Date() - date.setTime(date.getTime()+(days*24*60*60*1000)) - document.cookie = name+"="+val+"; expires="+date.toGMTString()+"; path=/" - end - - fun read_cookie(name:String):String do - var key = name + "=" - var ca = document.cookie.split(';') - for(var i=0; i 0 then score else null + app.data_store["s{str}"] = if score > 0 then score else null + var saved = game.grid.save + saved_str = saved + app.data_store["g{str}"] = saved + print "SAVE: {name}: {saved}" end + + # The saved player grid (to continue games) + var saved_str: nullable String = null end diff --git a/contrib/friendz/src/grid.nit b/contrib/friendz/src/grid.nit index a097ff5..3a141f6 100644 --- a/contrib/friendz/src/grid.nit +++ b/contrib/friendz/src/grid.nit @@ -191,14 +191,14 @@ class Grid fun save: String do var res = "" - var str = ".#ABCDEFGHI" + var str = ".abcdefghi#ABCDEFGHI" for y in [0..height[ do var rle = 0 var last: nullable Int = null for x in [0..width[ do var t = self.grid[x][y] - var tk = 0 - if t.fixed then tk = t.kind + 1 + var tk = t.kind + if t.fixed then tk += 10 if tk == last and rle<9 then rle += 1 else @@ -243,6 +243,7 @@ class Grid x += 1 else if c == '#' then var t = self.get(x,y) + assert t != null t.fixed = true x += 1 else if c >= 'A' and c <= 'I' then @@ -251,6 +252,11 @@ class Grid t.update(c.ascii-'A'.ascii+1) t.fixed = true x += 1 + else if c >= 'a' and c <= 'i' then + var t = self.get(x,y) + assert t != null + t.update(c.ascii-'a'.ascii+1) + x += 1 else if c >= '1' and c <= '9' then rle = c.to_i else @@ -261,7 +267,7 @@ class Grid if x>0 then y += 1 if x > mx then mx = x if y > my then my = y - if mx<3 or my<3 or mx>=max_width or my>=max_height then + if mx<3 or my<3 or mx>max_width or my>max_height then return false end self.resize(mx,my) diff --git a/contrib/friendz/src/level.nit b/contrib/friendz/src/level.nit index 9d8029e..b09f1f2 100644 --- a/contrib/friendz/src/level.nit +++ b/contrib/friendz/src/level.nit @@ -23,7 +23,7 @@ class Level var ls = code.split(";") self.number = i self.str = ls[0] - self.par = ls[1].to_i + self.gold = ls[1].to_i if ls.length >= 3 then self.status = ls[2] end @@ -47,8 +47,8 @@ class Level # initial grid position var str: String - # top score - var par: Int + # top score to get gold + var gold: Int # Help message if any var status: String = "" @@ -72,32 +72,28 @@ class Level var l_disabled = 1 var l_open = 2 var l_won = 3 - var l_par = 4 + var l_gold = 4 fun get_state: Int do if self.score == 0 then if self.number == 0 or game.levels[self.number-1].score > 0 then return l_open if self.number == 25 and game.levels[19].score > 0 then return l_open else return l_disabled - else if self.score < self.par or not game.levels[9].score > 0 then + else if self.score < self.gold or not game.levels[9].score > 0 then return l_won - else return l_par + else return l_gold end # Returns true if g is a wining condition for the level. fun check_won(g: Grid): Bool do - var w = g.won and (not self.is_challenge or g.number >= self.par) + var w = g.won and (not self.is_challenge or g.number >= self.gold) if not w then return false if g.number > self.score then self.score = g.number - self.save end return true end - - # Save the score of the level - fun save do end end # main game object diff --git a/contrib/opportunity/src/opportunity_controller.nit b/contrib/opportunity/src/opportunity_controller.nit index 868dd9e..26a4ef6 100644 --- a/contrib/opportunity/src/opportunity_controller.nit +++ b/contrib/opportunity/src/opportunity_controller.nit @@ -16,7 +16,6 @@ module opportunity_controller import nitcorn -import sha1 import templates import opportunity_model diff --git a/contrib/opportunity/src/opportunity_model.nit b/contrib/opportunity/src/opportunity_model.nit index ef7654d..cc72f23 100644 --- a/contrib/opportunity/src/opportunity_model.nit +++ b/contrib/opportunity/src/opportunity_model.nit @@ -247,7 +247,7 @@ class Meetup redef fun commit(db) do if id == "" then var time = get_time - var tmpid = (name + date + place + time.to_s).sha1_to_s + var tmpid = (name + date + place + time.to_s).sha1.hexdigest if not db.execute("INSERT INTO meetups (id, name, date, place, answer_mode) VALUES({tmpid.to_sql_string}, {name.html_escape.to_sql_string}, {date.html_escape.to_sql_string}, {place.html_escape.to_sql_string}, {answer_mode});") then print "Error recording entry Meetup {self}" print db.error or else "Null error" diff --git a/examples/rosettacode/sha_1.nit b/examples/rosettacode/sha_1.nit index 2eaf471..8776d48 100644 --- a/examples/rosettacode/sha_1.nit +++ b/examples/rosettacode/sha_1.nit @@ -9,4 +9,4 @@ module sha_1 import sha1 -print "Rosetta Code".sha1_to_s +print "Rosetta Code".sha1.hexdigest diff --git a/lib/base64.nit b/lib/base64.nit index 5f1c920..4eae395 100644 --- a/lib/base64.nit +++ b/lib/base64.nit @@ -17,88 +17,76 @@ # Offers the base 64 encoding and decoding algorithms module base64 -redef class String - +redef class NativeString # Alphabet used by the base64 algorithm - private fun base64_chars : String + private fun base64_chars : SequenceRead[Byte] do - return "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" + return "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".bytes end + + # Reversed alphabet for base64 private fun inverted_base64_chars : HashMap[Byte, Byte] do var inv_base64_chars = new HashMap[Byte, Byte] - for k in [0..base64_chars.bytelen[ do - inv_base64_chars[base64_chars.bytes[k]] = k.to_b + var l = base64_chars.length + for k in [0 .. l[ do + inv_base64_chars[base64_chars[k]] = k.to_b end return inv_base64_chars end - # Encodes the receiver string to base64. + # Encodes `self` to base64. + # # By default, uses "=" for padding. - fun encode_base64 : String do return encode_base64_custom_padding('='.ascii.to_b) - - # Encodes the receiver string to base64 using a custom padding character. # - # If using the default padding character `=`, see `encode_base64`. - fun encode_base64_custom_padding(padding : Byte) : String - do - var base64_bytes = once base64_chars.bytes - var length = bytelen - + # assert "string".encode_base64 == "c3RyaW5n" + private fun encode_base64(length: Int, padding: nullable Byte): Bytes do + var base64_bytes = once base64_chars + if padding == null then padding = '='.ascii.to_b var steps = length / 3 var bytes_in_last_step = length % 3 var result_length = steps * 4 if bytes_in_last_step > 0 then result_length += 4 - var result = new NativeString(result_length + 1) - var bytes = self.bytes - result[result_length] = 0u8 - - var mask_6bit = 0b0011_1111 + var result = new Bytes.with_capacity(result_length) + var in_off = 0 for s in [0 .. steps[ do - var e = 0 - for ss in [0 .. 3[ do - e += bytes[s * 3 + ss].to_i << ((2 - ss) * 8) - end - for ss in [0..4[ do - result[s * 4 + 3 - ss] = base64_bytes[(e >> (ss * 6)) & mask_6bit] - end + var ind = ((self[in_off] & 0b1111_1100u8) >> 2).to_i + result.add base64_bytes[ind] + ind = ((self[in_off] & 0b0000_0011u8) << 4).to_i | ((self[in_off + 1] & 0b1111_0000u8) >> 4).to_i + result.add base64_bytes[ind] + ind = ((self[in_off + 1] & 0b0000_1111u8) << 2).to_i | ((self[in_off + 2] & 0b1100_0000u8) >> 6).to_i + result.add base64_bytes[ind] + ind = (self[in_off + 2] & 0b0011_1111u8).to_i + result.add base64_bytes[ind] + in_off += 3 end - - var out_off = result_length - 4 - var in_off = length - bytes_in_last_step if bytes_in_last_step == 1 then - result[out_off] = base64_bytes[((bytes[in_off] & 0b1111_1100u8) >> 2).to_i] - result[out_off + 1] = base64_bytes[((bytes[in_off] & 0b0000_0011u8) << 4).to_i] - out_off += 2 + result.add base64_bytes[((self[in_off] & 0b1111_1100u8) >> 2).to_i] + result.add base64_bytes[((self[in_off] & 0b0000_0011u8) << 4).to_i] else if bytes_in_last_step == 2 then - result[out_off] = base64_bytes[((bytes[in_off] & 0b1111_1100u8) >> 2).to_i] - result[out_off + 1] = base64_bytes[(((bytes[in_off] & 0b0000_0011u8) << 4) | ((bytes[in_off + 1] & 0b1111_0000u8) >> 4)).to_i] - result[out_off + 2] = base64_bytes[((bytes[in_off + 1] & 0b0000_1111u8) << 2).to_i] - out_off += 3 - end - if bytes_in_last_step > 0 then - for i in [out_off .. result_length[ do result[i] = padding + result.add base64_bytes[((self[in_off] & 0b1111_1100u8) >> 2).to_i] + result.add base64_bytes[(((self[in_off] & 0b0000_0011u8) << 4) | ((self[in_off + 1] & 0b1111_0000u8) >> 4)).to_i] + result.add base64_bytes[((self[in_off + 1] & 0b0000_1111u8) << 2).to_i] end + var rempad = if bytes_in_last_step > 0 then 3 - bytes_in_last_step else 0 + for i in [0 .. rempad[ do result.add padding - return result.to_s_with_length(result_length) + return result end - # Decodes the receiver string from base64. - # By default, uses "=" for padding. - fun decode_base64 : String do return decode_base64_custom_padding('='.ascii.to_b) - - # Decodes the receiver string to base64 using a custom padding character. + # Decodes `self` from base64 # - # If using the default padding character `=`, see `decode_base64`. - fun decode_base64_custom_padding(padding : Byte) : String - do + # assert "c3RyaW5n".decode_base64 == "string" + # + # REQUIRE: `length % 4 == 0` + private fun decode_base64(length: Int, padding: nullable Byte): Bytes do + if padding == null then padding = '='.ascii.to_b var inv = once inverted_base64_chars - var length = bytelen - if length == 0 then return "" + if length == 0 then return new Bytes.empty assert length % 4 == 0 else print "base64::decode_base64 only supports strings of length multiple of 4" - var bytes = self.bytes + var bytes = self var steps = length / 4 var result_length = steps * 3 @@ -113,17 +101,16 @@ redef class String if padding_len == 1 then result_length -= 1 if padding_len == 2 then result_length -= 2 - var result = new NativeString(result_length + 1) - result[result_length] = 0u8 + var result = new Bytes.with_capacity(result_length + 1) for s in [0 .. steps[ do var c0 = inv[bytes[s * 4]] var c1 = inv[bytes[s * 4 + 1]] var c2 = inv[bytes[s * 4 + 2]] var c3 = inv[bytes[s * 4 + 3]] - result[s * 3] = ((c0 & 0b0011_1111u8) << 2) | ((c1 & 0b0011_0000u8) >> 4) - result[s * 3 + 1] = ((c1 & 0b0000_1111u8) << 4) | ((c2 & 0b0011_1100u8) >> 2) - result[s * 3 + 2] = ((c2 & 0b0000_0011u8) << 6) | (c3 & 0b0011_1111u8) + result.add (((c0 & 0b0011_1111u8) << 2) | ((c1 & 0b0011_0000u8) >> 4)) + result.add (((c1 & 0b0000_1111u8) << 4) | ((c2 & 0b0011_1100u8) >> 2)) + result.add (((c2 & 0b0000_0011u8) << 6) | (c3 & 0b0011_1111u8)) end var last_start = steps * 4 @@ -131,14 +118,52 @@ redef class String var c0 = inv[bytes[last_start]] var c1 = inv[bytes[last_start + 1]] var c2 = inv[bytes[last_start + 2]] - result[result_length - 2] = ((c0 & 0b0011_1111u8) << 2) | ((c1 & 0b0011_0000u8) >> 4) - result[result_length - 1] = ((c1 & 0b0000_1111u8) << 4) | ((c2 & 0b0011_1100u8) >> 2) + result.add (((c0 & 0b0011_1111u8) << 2) | ((c1 & 0b0011_0000u8) >> 4)) + result.add (((c1 & 0b0000_1111u8) << 4) | ((c2 & 0b0011_1100u8) >> 2)) else if padding_len == 2 then var c0 = inv[bytes[last_start]] var c1 = inv[bytes[last_start + 1]] - result[result_length - 1] = ((c0 & 0b0011_1111u8) << 2) | ((c1 & 0b0011_0000u8) >> 4) + result.add (((c0 & 0b0011_1111u8) << 2) | ((c1 & 0b0011_0000u8) >> 4)) end - return result.to_s_with_length(result_length) + return result + end +end + +redef class Bytes + + # Encodes the receiver string to base64 using a custom padding character. + # + # If using the default padding character `=`, see `encode_base64`. + fun encode_base64(padding: nullable Byte): Bytes + do + return items.encode_base64(length, padding) + end + + # Decodes the receiver string to base64 using a custom padding character. + # + # Default padding character `=` + fun decode_base64(padding : nullable Byte) : Bytes + do + return items.decode_base64(length, padding) + end +end + +redef class String + + # Encodes the receiver string to base64 using a custom padding character. + # + # If using the default padding character `=`, see `encode_base64`. + fun encode_base64(padding: nullable Byte): String + do + return to_cstring.encode_base64(bytelen, padding).to_s + end + + # Decodes the receiver string to base64 using a custom padding character. + # + # Default padding character `=` + fun decode_base64(padding : nullable Byte) : String + do + return to_cstring.decode_base64(bytelen, padding).to_s end end diff --git a/lib/core/bytes.nit b/lib/core/bytes.nit index 59c4c5f..356f386 100644 --- a/lib/core/bytes.nit +++ b/lib/core/bytes.nit @@ -19,6 +19,61 @@ import kernel import collection::array intrude import text::flat +redef class Byte + # Write self as a string into `ns` at position `pos` + private fun add_digest_at(ns: NativeString, pos: Int) do + var tmp = (0xF0u8 & self) >> 4 + ns[pos] = if tmp >= 0x0Au8 then tmp + 0x37u8 else tmp + 0x30u8 + tmp = 0x0Fu8 & self + ns[pos + 1] = if tmp >= 0x0Au8 then tmp + 0x37u8 else tmp + 0x30u8 + end + + # Is `self` a valid hexadecimal digit (in ASCII) + # + # ~~~nit + # intrude import core::bytes + # assert not '/'.ascii.to_b.is_valid_hexdigit + # assert '0'.ascii.to_b.is_valid_hexdigit + # assert '9'.ascii.to_b.is_valid_hexdigit + # assert not ':'.ascii.to_b.is_valid_hexdigit + # assert not '@'.ascii.to_b.is_valid_hexdigit + # assert 'A'.ascii.to_b.is_valid_hexdigit + # assert 'F'.ascii.to_b.is_valid_hexdigit + # assert not 'G'.ascii.to_b.is_valid_hexdigit + # assert not '`'.ascii.to_b.is_valid_hexdigit + # assert 'a'.ascii.to_b.is_valid_hexdigit + # assert 'f'.ascii.to_b.is_valid_hexdigit + # assert not 'g'.ascii.to_b.is_valid_hexdigit + # ~~~ + private fun is_valid_hexdigit: Bool do + return (self >= 0x30u8 and self <= 0x39u8) or + (self >= 0x41u8 and self <= 0x46u8) or + (self >= 0x61u8 and self <= 0x66u8) + end + + # `self` as a hexdigit to its byte value + # + # ~~~nit + # intrude import core::bytes + # assert 0x39u8.hexdigit_to_byteval == 0x09u8 + # assert 0x43u8.hexdigit_to_byteval == 0x0Cu8 + # ~~~ + # + # REQUIRE: `self.is_valid_hexdigit` + private fun hexdigit_to_byteval: Byte do + if self >= 0x30u8 and self <= 0x39u8 then + return self - 0x30u8 + else if self >= 0x41u8 and self <= 0x46u8 then + return self - 0x37u8 + else if self >= 0x61u8 and self <= 0x66u8 then + return self - 0x57u8 + end + # Happens only if the requirement is not met. + # i.e. this abort is here to please the compiler + abort + end +end + # A buffer containing Byte-manipulation facilities # # Uses Copy-On-Write when persisted @@ -26,7 +81,7 @@ class Bytes super AbstractArray[Byte] # A NativeString being a char*, it can be used as underlying representation here. - private var items: NativeString + var items: NativeString # Number of bytes in the array redef var length @@ -63,6 +118,20 @@ class Bytes return items[i] end + # Returns self as a hexadecimal digest + fun hexdigest: String do + var elen = length * 2 + var ns = new NativeString(elen) + var i = 0 + var oi = 0 + while i < length do + self[i].add_digest_at(ns, oi) + i += 1 + oi += 2 + end + return new FlatString.full(ns, elen, 0, elen - 1, elen) + end + # var b = new Bytes.with_capacity(1) # b[0] = 101u8 # assert b.to_s == "e" @@ -146,80 +215,13 @@ class Bytes redef fun to_s do persisted = true var b = self - if not is_utf8 then - b = clean_utf8 - persisted = false - end - return new FlatString.with_infos(b.items, b.length, 0, b.length -1) + var r = b.items.to_s_with_length(length) + if r != items then persisted = false + return r end redef fun iterator do return new BytesIterator.with_buffer(self) - # Is the byte collection valid UTF-8 ? - fun is_utf8: Bool do - var charst = once [0x80u8, 0u8, 0xE0u8, 0xC0u8, 0xF0u8, 0xE0u8, 0xF8u8, 0xF0u8] - var lobounds = once [0, 0x80, 0x800, 0x10000] - var hibounds = once [0x7F, 0x7FF, 0xFFFF, 0x10FFFF] - var pos = 0 - var len = length - var mits = items - while pos < len do - var nxst = mits.length_of_char_at(pos) - var charst_index = (nxst - 1) * 2 - if mits[pos] & charst[charst_index] == charst[charst_index + 1] then - var c = mits.char_at(pos) - var cp = c.ascii - if cp <= hibounds[nxst - 1] and cp >= lobounds[nxst - 1] then - if cp >= 0xD800 and cp <= 0xDFFF or - cp == 0xFFFE or cp == 0xFFFF then return false - else - return false - end - else - return false - end - pos += nxst - end - return true - end - - # Cleans the bytes of `self` to be UTF-8 compliant - private fun clean_utf8: Bytes do - var charst = once [0x80u8, 0u8, 0xE0u8, 0xC0u8, 0xF0u8, 0xE0u8, 0xF8u8, 0xF0u8] - var badchar = once [0xEFu8, 0xBFu8, 0xBDu8] - var lobounds = once [0, 0x80, 0x800, 0x10000] - var hibounds = once [0x7F, 0x7FF, 0xFFFF, 0x10FFFF] - var pos = 0 - var len = length - var ret = new Bytes.with_capacity(len) - var mits = items - while pos < len do - var nxst = mits.length_of_char_at(pos) - var charst_index = (nxst - 1) * 2 - if mits[pos] & charst[charst_index] == charst[charst_index + 1] then - var c = mits.char_at(pos) - var cp = c.ascii - if cp <= hibounds[nxst - 1] and cp >= lobounds[nxst - 1] then - if cp >= 0xD800 and cp <= 0xDFFF or - cp == 0xFFFE or cp == 0xFFFF then - ret.append badchar - pos += 1 - else - var pend = pos + nxst - for i in [pos .. pend[ do ret.add mits[i] - pos += nxst - end - else - ret.append badchar - pos += 1 - end - else - ret.append badchar - pos += 1 - end - end - return ret - end end private class BytesIterator @@ -231,7 +233,7 @@ private class BytesIterator var max: Int - init with_buffer(b: Bytes) do init(b.items, 0, b.length - 1) + init with_buffer(b: Bytes) do init(b.items, 0, b.length) redef fun is_ok do return index < max @@ -253,6 +255,15 @@ redef class Text return b end + # Is `self` a valid hexdigest ? + # + # assert "0B1d3F".is_valid_hexdigest + # assert not "5G".is_valid_hexdigest + fun is_valid_hexdigest: Bool do + for i in bytes do if not i.is_valid_hexdigit then return false + return true + end + # Appends `self.bytes` to `b` fun append_to_bytes(b: Bytes) do for s in substrings do @@ -260,6 +271,24 @@ redef class Text b.append_ns_from(s.items, s.bytelen, from) end end + + # Returns a new `Bytes` instance with the digest as content + # + # assert "0B1F4D".hexdigest_to_bytes == [0x0Bu8, 0x1Fu8, 0x4Du8] + # + # REQUIRE: `self` is a valid hexdigest and hexdigest.length % 2 == 0 + fun hexdigest_to_bytes: Bytes do + var b = bytes + var pos = 0 + var max = bytelen + var ret = new Bytes.with_capacity(max / 2) + while pos < max do + ret.add((b[pos].hexdigit_to_byteval << 4) | + b[pos + 1].hexdigit_to_byteval) + pos += 2 + end + return ret + end end redef class FlatText diff --git a/lib/core/stream.nit b/lib/core/stream.nit index 2db319a..4b1e826 100644 --- a/lib/core/stream.nit +++ b/lib/core/stream.nit @@ -173,12 +173,13 @@ abstract class Reader # ~~~ fun read_all: String do var s = read_all_bytes - if not s.is_utf8 then s = s.clean_utf8 var slen = s.length if slen == 0 then return "" var rets = "" var pos = 0 - var sits = s.items + var str = s.items.clean_utf8(slen) + slen = str.bytelen + var sits = str.items var remsp = slen while pos < slen do # The 129 size was decided more or less arbitrarily diff --git a/lib/core/text/flat.nit b/lib/core/text/flat.nit index c8b6ecd..52de988 100644 --- a/lib/core/text/flat.nit +++ b/lib/core/text/flat.nit @@ -985,8 +985,7 @@ redef class NativeString redef fun to_s_with_length(length): FlatString do assert length >= 0 - var str = new FlatString.with_infos(self, length, 0, length - 1) - return str + return clean_utf8(length) end redef fun to_s_full(bytelen, unilen) do @@ -997,6 +996,8 @@ redef class NativeString redef fun to_s_with_copy: FlatString do var length = cstring_length + var r = clean_utf8(length) + if r.items != self then return r var new_self = new NativeString(length + 1) copy_to(new_self, length, 0, 0) var str = new FlatString.with_infos(new_self, length, 0, length - 1) @@ -1005,6 +1006,81 @@ redef class NativeString return str end + # Cleans a NativeString if necessary + fun clean_utf8(len: Int): FlatString do + var replacements: nullable Array[Int] = null + var end_length = len + var pos = 0 + var chr_ln = 0 + while pos < len do + var b = self[pos] + var nxst = length_of_char_at(pos) + var ok_st: Bool + if nxst == 1 then + ok_st = b & 0x80u8 == 0u8 + else if nxst == 2 then + ok_st = b & 0xE0u8 == 0xC0u8 + else if nxst == 3 then + ok_st = b & 0xF0u8 == 0xE0u8 + else + ok_st = b & 0xF8u8 == 0xF0u8 + end + if not ok_st then + if replacements == null then replacements = new Array[Int] + replacements.add pos + end_length += 2 + pos += 1 + chr_ln += 1 + continue + end + var ok_c: Bool + var c = char_at(pos) + var cp = c.ascii + if nxst == 1 then + ok_c = cp >= 0 and cp <= 0x7F + else if nxst == 2 then + ok_c = cp >= 0x80 and cp <= 0x7FF + else if nxst == 3 then + ok_c = cp >= 0x800 and cp <= 0xFFFF + ok_c = ok_c and not (cp >= 0xD800 and cp <= 0xDFFF) and cp != 0xFFFE and cp != 0xFFFF + else + ok_c = cp >= 0x10000 and cp <= 0x10FFFF + end + if not ok_c then + if replacements == null then replacements = new Array[Int] + replacements.add pos + end_length += 2 + pos += 1 + chr_ln += 1 + continue + end + pos += c.u8char_len + chr_ln += 1 + end + var ret = self + if end_length != len then + ret = new NativeString(end_length) + var old_repl = 0 + var off = 0 + var repls = replacements.as(not null) + var r = repls.items.as(not null) + var imax = repls.length + for i in [0 .. imax[ do + var repl_pos = r[i] + var chkln = repl_pos - old_repl + copy_to(ret, chkln, old_repl, off) + off += chkln + ret[off] = 0xEFu8 + ret[off + 1] = 0xBFu8 + ret[off + 2] = 0xBDu8 + old_repl = repl_pos + 1 + off += 3 + end + copy_to(ret, len - old_repl, old_repl, off) + end + return new FlatString.full(ret, end_length, 0, end_length - 1, chr_ln) + end + # Sets the next bytes at position `pos` to the value of `c`, encoded in UTF-8 # # Very unsafe, make sure to have room for this char prior to calling this function. @@ -1109,7 +1185,7 @@ redef class Array[E] end i += 1 end - return ns.to_s_with_length(sl) + return new FlatString.with_infos(ns, sl, 0, sl - 1) end end @@ -1146,7 +1222,7 @@ redef class NativeArray[E] end i += 1 end - return ns.to_s_with_length(sl) + return new FlatString.with_infos(ns, sl, 0, sl - 1) end end diff --git a/lib/matrix/matrix.nit b/lib/matrix/matrix.nit new file mode 100644 index 0000000..73131ca --- /dev/null +++ b/lib/matrix/matrix.nit @@ -0,0 +1,295 @@ +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Services for matrices of `Float` values +module matrix + +# A rectangular array of `Float` +# +# Require: `width > 0 and height > 0` +class Matrix + super Cloneable + + # Number of columns + var width: Int + + # Number of rows + var height: Int + + # Items of this matrix, rows by rows + private var items: Array[Float] is lazy do + return new Array[Float].filled_with(0.0, width*height) + end + + # Create a matrix from nested sequences + # + # Require: all rows are of the same length + # + # ~~~ + # var matrix = new Matrix.from([[1.0, 2.0], + # [3.0, 4.0]]) + # assert matrix.to_s == """ + # 1.0 2.0 + # 3.0 4.0""" + # ~~~ + init from(items: SequenceRead[SequenceRead[Float]]) + do + if items.is_empty then + init(0, 0) + return + end + + init(items.first.length, items.length) + + for j in height.times do assert items[j].length == width + + for j in height.times do + for i in width.times do + self[j, i] = items[j][i] + end + end + end + + # Get each row of this matrix in nested arrays + # + # ~~~ + # var items = [[1.0, 2.0], + # [3.0, 4.0]] + # var matrix = new Matrix.from(items) + # assert matrix.to_a == items + # ~~~ + fun to_a: Array[Array[Float]] + do + var a = new Array[Array[Float]] + for j in height.times do + var row = new Array[Float] + for i in width.times do + row.add self[j, i] + end + a.add row + end + return a + end + + # Create a matrix from an `Array[Float]` composed of rows after rows + # + # Require: `width > 0 and height > 0` + # Require: `array.length >= width*height` + # + # ~~~ + # var matrix = new Matrix.from_array(2, 2, [1.0, 2.0, + # 3.0, 4.0]) + # assert matrix.to_s == """ + # 1.0 2.0 + # 3.0 4.0""" + # ~~~ + init from_array(width, height: Int, array: SequenceRead[Float]) + do + assert width > 0 + assert height > 0 + assert array.length >= width*height + + init(width, height) + + for i in height.times do + for j in width.times do + self[j, i] = array[i + j*width] + end + end + end + + # Create an identity matrix + # + # Require: `size >= 0` + # + # ~~~ + # var i = new Matrix.identity(3) + # assert i.to_s == """ + # 1.0 0.0 0.0 + # 0.0 1.0 0.0 + # 0.0 0.0 1.0""" + # ~~~ + new identity(size: Int) + do + assert size >= 0 + + var matrix = new Matrix(size, size) + for i in size.times do + for j in size.times do + matrix[j, i] = if i == j then 1.0 else 0.0 + end + end + return matrix + end + + # Create a new clone of this matrix + redef fun clone do return new Matrix.from_array(width, height, items.clone) + + # Get the value at column `y` and row `x` + # + # Require: `x >= 0 and x <= width and y >= 0 and y <= height` + # + # ~~~ + # var matrix = new Matrix.from([[0.0, 0.1], + # [1.0, 1.1]]) + # + # assert matrix[0, 0] == 0.0 + # assert matrix[0, 1] == 0.1 + # assert matrix[1, 0] == 1.0 + # assert matrix[1, 1] == 1.1 + # ~~~ + fun [](y, x: Int): Float + do + assert x >= 0 and x < width + assert y >= 0 and y < height + + return items[x + y*width] + end + + # Set the `value` at row `y` and column `x` + # + # Require: `x >= 0 and x <= width and y >= 0 and y <= height` + # + # ~~~ + # var matrix = new Matrix.identity(2) + # + # matrix[0, 0] = 0.0 + # matrix[0, 1] = 0.1 + # matrix[1, 0] = 1.0 + # matrix[1, 1] = 1.1 + # + # assert matrix.to_s == """ + # 0.0 0.1 + # 1.0 1.1""" + # ~~~ + fun []=(y, x: Int, value: Float) + do + assert x >= 0 and x < width + assert y >= 0 and y < height + + items[x + y*width] = value + end + + # Matrix product (×) + # + # Require: `self.width == other.height` + # + # ~~~ + # var m = new Matrix.from([[3.0, 4.0], + # [5.0, 6.0]]) + # var i = new Matrix.identity(2) + # + # assert m * i == m + # assert (m * m).to_s == """ + # 29.0 36.0 + # 45.0 56.0""" + # + # var a = new Matrix.from([[1.0, 2.0, 3.0], + # [4.0, 5.0, 6.0]]) + # var b = new Matrix.from([[1.0], + # [2.0], + # [3.0]]) + # var c = a * b + # assert c.to_s == """ + # 14.0 + # 32.0""" + # ~~~ + fun *(other: Matrix): Matrix + do + assert self.width == other.height + + var out = new Matrix(other.width, self.height) + for j in self.height.times do + for i in other.width.times do + var sum = items.first.zero + for k in self.width.times do sum += self[j, k] * other[k, i] + out[j, i] = sum + end + end + return out + end + + # Get the transpose of this matrix + # + # ~~~ + # var matrix = new Matrix.from([[1.0, 2.0, 3.0], + # [4.0, 5.0, 6.0]]) + # assert matrix.transposed.to_a == [[1.0, 4.0], + # [2.0, 5.0], + # [3.0, 6.0]] + # + # var i = new Matrix.identity(3) + # assert i.transposed == i + # ~~~ + fun transposed: Matrix + do + var out = new Matrix(height, width) + for k, v in self do out[k.x, k.y] = v + return out + end + + # Iterate over the values in this matrix + fun iterator: MapIterator[MatrixCoordinate, Float] do return new MatrixIndexIterator(self) + + redef fun to_s + do + var lines = new Array[String] + for y in height.times do + lines.add items.subarray(y*width, width).join(" ") + end + return lines.join("\n") + end + + redef fun ==(other) do return other isa Matrix and other.items == self.items + redef fun hash do return items.hash +end + +private class MatrixIndexIterator + super MapIterator[MatrixCoordinate, Float] + + var matrix: Matrix + + redef var key = new MatrixCoordinate(0, 0) + + redef fun is_ok do return key.y < matrix.height + + redef fun item + do + assert is_ok + return matrix[key.y, key.x] + end + + redef fun next + do + assert is_ok + var key = key + if key.x == matrix.width - 1 then + key.x = 0 + key.y += 1 + else + key.x += 1 + end + end +end + +# Position key when iterating over the values of a matrix +class MatrixCoordinate + # Index of the current column + var x: Int + + # Index of the current row + var y: Int + + redef fun to_s do return "({x},{y})" +end diff --git a/lib/matrix/package.ini b/lib/matrix/package.ini new file mode 100644 index 0000000..4bd9013 --- /dev/null +++ b/lib/matrix/package.ini @@ -0,0 +1,11 @@ +[package] +name=matrix +tags=lib +maintainer=Alexis Laferrière +license=Apache-2.0 +[upstream] +browse=https://github.com/nitlang/nit/tree/master/lib/matrix/ +git=https://github.com/nitlang/nit.git +git.directory=lib/matrix/ +homepage=http://nitlanguage.org +issues=https://github.com/nitlang/nit/issues diff --git a/lib/matrix/projection.nit b/lib/matrix/projection.nit new file mode 100644 index 0000000..908761a --- /dev/null +++ b/lib/matrix/projection.nit @@ -0,0 +1,153 @@ +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Services on `Matrix` to transform and project 3D coordinates +module projection + +intrude import matrix + +redef class Matrix + + # Create an orthogonal projection matrix + # + # `left, right, bottom, top, near, far` defines the world clip planes. + new orthogonal(left, right, bottom, top, near, far: Float) + do + var dx = right - left + var dy = top - bottom + var dz = far - near + + assert dx != 0.0 and dy != 0.0 and dz != 0.0 + + var mat = new Matrix.identity(4) + mat[0, 0] = 2.0 / dx + mat[3, 0] = -(right + left) / dx + mat[1, 1] = 2.0 / dy + mat[3, 1] = -(top + bottom) / dy + mat[2, 2] = 2.0 / dz + mat[3, 2] = -(near + far) / dz + return mat + end + + # Create a perspective transformation matrix + # + # Using the given vertical `field_of_view_y` in radians, the `aspect_ratio` + # and the `near`/`far` world distances. + new perspective(field_of_view_y, aspect_ratio, near, far: Float) + do + var frustum_height = (field_of_view_y/2.0).tan * near + var frustum_width = frustum_height * aspect_ratio + + return new Matrix.frustum(-frustum_width, frustum_width, + -frustum_height, frustum_height, + near, far) + end + + # Create a frustum transformation matrix + # + # `left, right, bottom, top, near, far` defines the world clip planes. + new frustum(left, right, bottom, top, near, far: Float) + do + var dx = right - left + var dy = top - bottom + var dz = far - near + + assert near > 0.0 + assert far > 0.0 + assert dx > 0.0 + assert dy > 0.0 + assert dz > 0.0 + + var mat = new Matrix(4, 4) + + mat[0, 0] = 2.0 * near / dx + mat[0, 1] = 0.0 + mat[0, 2] = 0.0 + mat[0, 3] = 0.0 + + mat[1, 0] = 0.0 + mat[1, 1] = 2.0 * near / dy + mat[1, 2] = 0.0 + mat[1, 3] = 0.0 + + mat[2, 0] = (right + left) / dx + mat[2, 1] = (top + bottom) / dy + mat[2, 2] = -(near + far) / dz + mat[2, 3] = -1.0 + + mat[3, 0] = 0.0 + mat[3, 1] = 0.0 + mat[3, 2] = -2.0 * near * far / dz + mat[3, 3] = 0.0 + + return mat + end + + # Apply a translation by `x, y, z` to this matrix + fun translate(x, y, z: Float) + do + for i in [0..3] do + self[3, i] = self[3,i] + self[0, i] * x + self[1, i] * y + self[2, i] * z + end + end + + # Apply scaling on `x, y, z` to this matrix + fun scale(x, y, z: Float) + do + for i in [0..3] do + self[0, i] = self[0, i] * x + self[1, i] = self[1, i] * y + self[2, i] = self[2, i] * z + end + end + + # Create a rotation matrix by `angle` around the vector defined by `x, y, z` + new rotation(angle, x, y, z: Float) + do + var mat = new Matrix.identity(4) + + var mag = (x*x + y*y + z*z).sqrt + var sin = angle.sin + var cos = angle.cos + + if mag > 0.0 then + x = x / mag + y = y / mag + z = z / mag + + var inv_cos = 1.0 - cos + + mat[0, 0] = inv_cos*x*x + cos + mat[0, 1] = inv_cos*x*y - z*sin + mat[0, 2] = inv_cos*z*x + y*sin + + mat[1, 0] = inv_cos*x*y + z*sin + mat[1, 1] = inv_cos*y*y + cos + mat[1, 2] = inv_cos*y*z - x*sin + + mat[2, 0] = inv_cos*z*x - y*sin + mat[2, 1] = inv_cos*y*z + x*sin + mat[2, 2] = inv_cos*z*z + cos + end + return mat + end + + # Apply a rotation of `angle` radians around the vector `x, y, z` + fun rotate(angle, x, y, z: Float) + do + var rotation = new Matrix.rotation(angle, x, y, z) + var rotated = self * rotation + self.items = rotated.items + end +end diff --git a/lib/sha1.nit b/lib/sha1.nit index 8a5acc9..2bd8fbe 100644 --- a/lib/sha1.nit +++ b/lib/sha1.nit @@ -1,7 +1,5 @@ # This file is part of NIT (http://www.nitlanguage.org). # -# Copyright 2014 Lucas Bajolet -# # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at @@ -219,22 +217,12 @@ in "C Header" `{ } `} -redef class String - - # Computes the SHA1 of the receiver - # - # Returns a digest of 20 bytes as a String, - # note that all the characters are not necessarily ASCII. - # If you want the hex string version of the digest, use - # sha1_to_s. - # - # import base64 - # assert "The quick brown fox jumps over the lazy dog".sha1.encode_base64 == "L9ThxnotKPzthJ7hu3bnORuT6xI=" - fun sha1: String import String.to_cstring, String.length, NativeString.to_s_with_length `{ +redef class NativeString + private fun sha1_intern(len: Int): NativeString `{ sha1nfo s; sha1_init(&s); - sha1_write(&s, String_to_cstring(self), String_length(self)); + sha1_write(&s, self, len); uint8_t* digest = sha1_result(&s); char* digested = malloc(21); @@ -243,35 +231,30 @@ redef class String digested[20] = '\0'; - return NativeString_to_s_with_length(digested, 20); + return digested; `} +end + +redef class String + + # Computes the SHA1 of the receiver + # + # Returns a digest of 20 bytes as a NativeString, + # note that all the characters are not necessarily ASCII. + # If you want the hex string version of the digest, use + # sha1_hexdigest. + # + # import base64 + # assert "The quick brown fox jumps over the lazy dog".sha1 == [0x2Fu8, 0xD4u8, 0xE1u8, 0xC6u8, 0x7Au8, 0x2Du8, 0x28u8, 0xFCu8, 0xEDu8, 0x84u8, 0x9Eu8, 0xE1u8, 0xBBu8, 0x76u8, 0xE7u8, 0x39u8, 0x1Bu8, 0x93u8, 0xEBu8, 0x12u8] + fun sha1: Bytes do + return new Bytes(to_cstring.sha1_intern(bytelen), 20, 20) + end # Computes the SHA1 of the receiver. # # Returns a 40 char String containing the Hexadecimal # Digest in its Char form. # - # assert "The quick brown fox jumps over the lazy dog".sha1_to_s == "2FD4E1C67A2D28FCED849EE1BB76E7391B93EB12" - fun sha1_to_s: String import String.to_cstring, String.length, NativeString.to_s_with_length `{ - sha1nfo s; - - sha1_init(&s); - sha1_write(&s, String_to_cstring(self), String_length(self)); - uint8_t* digest = sha1_result(&s); - - char* ret_str = malloc(41); - char* hexmap = "0123456789ABCDEF"; - - int i; - for(i=0;i<20;i++){ - uint8_t q = digest[i]; - ret_str[i*2] = hexmap[q >> 4]; - ret_str[(i*2)+1] = hexmap[q & 0x0F]; - } - ret_str[40] = '\0'; - - return NativeString_to_s_with_length(ret_str, 40); - `} - + # assert "The quick brown fox jumps over the lazy dog".sha1_hexdigest == "2FD4E1C67A2D28FCED849EE1BB76E7391B93EB12" + fun sha1_hexdigest: String do return sha1.hexdigest end - diff --git a/lib/websocket/websocket.nit b/lib/websocket/websocket.nit index c3fdaad..2a3c32f 100644 --- a/lib/websocket/websocket.nit +++ b/lib/websocket/websocket.nit @@ -114,7 +114,7 @@ class WebsocketConnection resp_map["Connection:"] = "Upgrade" var key = heads["Sec-WebSocket-Key"] key += "258EAFA5-E914-47DA-95CA-C5AB0DC85B11" - key = key.sha1.encode_base64 + key = key.sha1.encode_base64.to_s resp_map["Sec-WebSocket-Accept:"] = key var resp = resp_map.join("\r\n", " ") resp += "\r\n\r\n" diff --git a/misc/README.md b/misc/README.md index 9b4bf06..8d09d74 100644 --- a/misc/README.md +++ b/misc/README.md @@ -102,7 +102,7 @@ The command `:Nitdoc` searches the documentation for the word under the cursor. The results are displayed in the preview window in order of relevance. You can search for any word by passing it as an argument, as in `:Nitdoc modulo`. The Nitdoc command uses the same metadata files as the omnifunc. -You may want to map the function to a shortcut by adding the following code to `~/.vimrc`. +You may want to map the command to a shortcut by adding the following code to `~/.vimrc`. ~~~ " Map displaying Nitdoc to Ctrl-D @@ -119,3 +119,18 @@ You may want to map the function to a shortcut by adding the following code to ` " Map the NitGitGrep function to Ctrl-G map :call NitGitGrep() ~~~ + +## Execute the current file + +The command `:NitExecute` calls `nit` to interpret the current file. + +If modified, the current buffer is saved to a temporary file before being executed. +This may cause failures if the current buffer imports modules relative to the source package. +In such cases, save the file before calling `:NitExecute`. + +You may want to map the command to a shortcut by adding the following code to `~/.vimrc`. + +~~~ +" Map the NitExecute function to Ctrl-F +map :NitExecute +~~~ diff --git a/misc/vim/plugin/nit.vim b/misc/vim/plugin/nit.vim index 363a8f9..6824882 100644 --- a/misc/vim/plugin/nit.vim +++ b/misc/vim/plugin/nit.vim @@ -382,6 +382,19 @@ fun NitGitGrep() redraw! endfun +" Call `nit` on the current file +fun NitExecute() + let path = expand('%') + + if &modified + let path = tempname() . '.nit' + execute '%write '. path + endif + + execute '!nit "' . path . '"' +endfun +command NitExecute call NitExecute() + if !exists("g:nit_disable_omnifunc") || !g:nit_disable_omnifunc " Activate the omnifunc on Nit files autocmd FileType nit set omnifunc=NitOmnifunc diff --git a/src/nitcatalog.nit b/src/nitcatalog.nit index ba0cb1c..28ae918 100644 --- a/src/nitcatalog.nit +++ b/src/nitcatalog.nit @@ -86,6 +86,12 @@ class CatalogPage # Placeholder to include additional things before the ``. var more_head = new Template + # Relative path to the root directory (with the index file). + # + # Use "" for pages in the root directory + # Use ".." for pages in a subdirectory + var rootpath: String + redef init do add """ @@ -94,7 +100,7 @@ class CatalogPage - + """ add more_head @@ -116,7 +122,7 @@ class CatalogPage @@ -270,7 +276,7 @@ class Catalog # Compute information and generate a full HTML page for a package fun package_page(mpackage: MPackage): Writable do - var res = new CatalogPage + var res = new CatalogPage("..") var score = score[mpackage].to_f var name = mpackage.name.html_escape res.more_head.add """{{{name}}}""" @@ -369,7 +375,7 @@ class Catalog if cat == null then cat = t tag2proj[t].add mpackage t = t.html_escape - ts2.add "{t}" + ts2.add "{t}" end res.add_list(ts2, ", ", ", ") end @@ -377,7 +383,7 @@ class Catalog var t = "none" cat = t tag2proj[t].add mpackage - res.add "{t}" + res.add "{t}" end if cat != null then cat2proj[cat].add mpackage score += ts2.length.score @@ -496,7 +502,7 @@ class Catalog fun li_package(p: MPackage): String do var res = "" - var f = "{p.name}.html" + var f = "p/{p.name}.html" res += "{p}" var d = p.mdoc_or_fallback if d != null then res += " - {d.html_synopsis.write_to_string}" @@ -614,7 +620,7 @@ class Catalog res.add "" for p in mpackages do res.add "" - res.add "{p.name}" + res.add "{p.name}" var maint = "?" if p.maintainers.not_empty then maint = p.maintainers.first res.add "{maint}" @@ -700,7 +706,7 @@ if not opt_no_model.value then end var out = opt_dir.value or else "catalog.out" -out.mkdir +(out/"p").mkdir # Generate the css (hard coded) var css = """ @@ -806,13 +812,13 @@ css.write_to_file(out/"style.css") for p in model.mpackages do # print p - var f = "{p.name}.html" + var f = "p/{p.name}.html" catalog.package_page(p).write_to_file(out/f) end # INDEX -var index = new CatalogPage +var index = new CatalogPage("") index.more_head.add "Packages in Nit" index.add """ @@ -859,7 +865,7 @@ index.write_to_file(out/"index.html") # PEOPLE -var page = new CatalogPage +var page = new CatalogPage("") page.more_head.add "People of Nit" page.add """
\n

People of Nit

\n""" page.add "

By Maintainer

\n" @@ -871,7 +877,7 @@ page.write_to_file(out/"people.html") # TABLE -page = new CatalogPage +page = new CatalogPage("") page.more_head.add "Projets of Nit" page.add """
\n

People of Nit

\n""" page.add "

Table of Projets

\n" diff --git a/tests/sav/nitcg/test_text_stat.res b/tests/sav/nitcg/test_text_stat.res index 1066456..ff641cc 100644 --- a/tests/sav/nitcg/test_text_stat.res +++ b/tests/sav/nitcg/test_text_stat.res @@ -21,7 +21,7 @@ Calls to bytepos for each type: FlatString = 18 Calls to first_byte on FlatString 153 Calls to last_byte on FlatString 103 -FlatStrings allocated with length 81 (85.417%) +FlatStrings allocated with length 82 (86.458%) Length of travel for index distribution: * null = 20 => occurences 83.333%, cumulative 83.333% * 1 = 8 => occurences 21.053%, cumulative 73.684% diff --git a/tests/sav/nitserial_args1.res b/tests/sav/nitserial_args1.res index fe675df..ce7118b 100644 --- a/tests/sav/nitserial_args1.res +++ b/tests/sav/nitserial_args1.res @@ -13,6 +13,7 @@ redef class Deserializer if name == "Array[nullable Object]" then return new Array[nullable Object].from_deserializer(self) if name == "Array[Serializable]" then return new Array[Serializable].from_deserializer(self) if name == "Array[Object]" then return new Array[Object].from_deserializer(self) + if name == "Array[Int]" then return new Array[Int].from_deserializer(self) if name == "Array[Match]" then return new Array[Match].from_deserializer(self) if name == "Array[nullable Match]" then return new Array[nullable Match].from_deserializer(self) return super diff --git a/tests/sav/test_bytes_hexdigit.res b/tests/sav/test_bytes_hexdigit.res new file mode 100644 index 0000000..f00af0c --- /dev/null +++ b/tests/sav/test_bytes_hexdigit.res @@ -0,0 +1,3 @@ +0x0b +0x1f +0x4d diff --git a/tests/sav/test_text_stat.res b/tests/sav/test_text_stat.res index 49e9adc..f6e7b69 100644 --- a/tests/sav/test_text_stat.res +++ b/tests/sav/test_text_stat.res @@ -21,7 +21,7 @@ Calls to bytepos for each type: FlatString = 18 Calls to first_byte on FlatString 153 Calls to last_byte on FlatString 103 -FlatStrings allocated with length 81 (85.417%) +FlatStrings allocated with length 82 (86.458%) Length of travel for index distribution: * 0 = 20 => occurences 83.333%, cumulative 83.333% * 1 = 8 => occurences 21.053%, cumulative 73.684% diff --git a/tests/test_bytes_hexdigit.nit b/tests/test_bytes_hexdigit.nit new file mode 100644 index 0000000..28f51e3 --- /dev/null +++ b/tests/test_bytes_hexdigit.nit @@ -0,0 +1,17 @@ +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +var s = "0B1F4D".hexdigest_to_bytes + +for i in s do print i