If Object defines a virtual type SELF, redefines it automatically in all subclasses. Also checks for some conditions on the declaration of SELF: it must be public, it must not be fixed and it must be declared on Object (or not declared at all). These conditions ensures that its refinements are valid.
The error messages when trying to redefining SELF could be improved. Maybe adding a special case preventing any redef of SELF?
Pull-Request: #902
Reviewed-by: Jean Privat <jean@pryen.org>
Reviewed-by: Etienne M. Gagnon <egagnon@j-meg.com>
Reviewed-by: Lucas Bajolet <r4pass@hotmail.com>
Reviewed-by: Alexandre Terrasa <alexandre@moz-code.org>
end
redef class Array[E]
- super StringCapable
-
redef fun to_s: String do
var l = length
var its = _items
na[i] = tmp
i += 1
end
- var ns = calloc_string(sl + 1)
+ var ns = new NativeString(sl + 1)
ns[sl] = '\0'
i = 0
var off = 0
fun measureText(str: String, height: Int): Int
do
var font = app.game.font
- return str.length * (app.game.font.width + app.game.font.hspace)
+ return str.length * (font.width + font.hspace.to_i)
end
# displays a debug rectangle
redef class Object
# Factorize cast
- fun json_as_a: Array[nullable Object] do return self.as(Array[nullable Object])
+ fun json_as_a: JsonArray do return self.as(JsonArray)
# Factorize cast
- fun json_as_map: Map[String, nullable Object] do return self.as(Map[String, nullable Object])
+ fun json_as_map: JsonObject do return self.as(JsonObject)
end
redef class GithubCurl
# Get a given pull request (PR)
- fun getpr(number: Int): Map[String, nullable Object]
+ fun getpr(number: Int): JsonObject
do
var pr = get_and_check("https://api.github.com/repos/privat/nit/pulls/{number}")
var prm = pr.json_as_map
end
# Get reviewers of a PR
- fun getrev(pr: Map[String, nullable Object]): Array[String]
+ fun getrev(pr: JsonObject): Array[String]
do
var number = pr["number"].as(Int)
var user = pr["user"].json_as_map["login"].as(String)
import github_api
-# The proprieties introduced by this redef are to be used only on HashMap
+# The proprieties introduced by this redef are to be used only on a JSON object
# representing a Github repository.
-redef class HashMap[K, V]
+redef class JsonObject
# The repository has at least 50% Java code
fun has_lots_of_java: Bool
do
- assert self isa HashMap[String, nullable Object]
var java_count = 0
if keys.has("Java") then java_count = self["Java"].as(Int)
# The repository has at least 100 lines of C code
fun has_some_c: Bool
do
- assert self isa HashMap[String, nullable Object]
var c_count = 0
if keys.has("C") then c_count = self["C"].as(Int)
return c_count > 100
loop
# Get a page of the main query
var uri = "https://api.github.com/search/repositories?q={main_query}&page={page}&per_page={per_page}&sort=stars"
- var obj = curl.get_and_check(uri).as(HashMap[String, nullable Object])
+ var obj = curl.get_and_check(uri).as(JsonObject)
# Main object has "total_count" and "items"
- var items = obj["items"].as(Array[nullable Object])
+ var items = obj["items"].as(JsonArray)
# "items" is an array of Json objects
for item in items do
- assert item isa HashMap[String, nullable Object]
+ assert item isa JsonObject
# Each item has "name" and "languages_url"
assert item.keys.has("name")
# Download the language list
var lang_url = item["languages_url"].as(String)
- var langs = curl.get_and_check(lang_url).as(HashMap[String, nullable Object])
+ var langs = curl.get_and_check(lang_url).as(JsonObject)
# The project is of interest if it has lots of Java and at least some C
var may_be_of_interest = langs.has_lots_of_java and langs.has_some_c
exp = e d+;
e = ('e'|'E') ('+'|'-')?;
-string = '"' (Any-'\\'-'"' | '\\'Any)* '"';
+hexdig = '0'..'9' | 'a'..'z' | 'A'..'Z';
+string = '"' (Any - '\\' - '"' | '\\' (
+ '\\' |
+ '"' |
+ '/' |
+ 'b' |
+ 'f' |
+ 'n' |
+ 'r' |
+ 't' |
+ 'u' hexdig hexdig hexdig hexdig
+ ))* '"';
blank = (' '|'\n'|'\t')+;
var mname = request.string_arg("meetup_name")
var mdate = request.string_arg("meetup_date")
var mplace = request.string_arg("meetup_place")
+ var mmodestr = request.string_arg("meetup_mode")
+ var mmode = 0
if mdate == null then mdate = ""
if mplace == null then mplace = ""
+ if mmodestr != null then
+ mmode = 1
+ end
if mname == null then
mname = ""
var rsp = new HttpResponse(200)
var meetpage = new MeetupCreationPage
- var meet = new Meetup(mname, mdate, mplace)
+ var meet = new Meetup(mname, mdate, mplace, mmode)
meetpage.ans = ansset
meetpage.meet = meet
meetpage.error = "'Meetup name' is a mandatory fields."
end
var db = new OpportunityDB.open(db_path)
- var meet = new Meetup(mname, mdate, mplace)
+ var meet = new Meetup(mname, mdate, mplace, mmode)
if ansset.is_empty then
db.close
var rsp = new HttpResponse(200)
redef fun answer(request, uri) do
var persid = request.int_arg("pers_id")
var ansid = request.int_arg("answer_id")
- var ans = request.bool_arg("answer")
+ var ans = request.int_arg("answer")
if persid == null or ansid == null or ans == null then return bad_req
var db = new OpportunityDB.open(db_path)
db.change_answer(ansid, persid, ans)
var ans = request.string_arg("answers").split("&")
if name == null or m_id == null then return bad_req
print ans
- var ansmap = new HashMap[Int, Bool]
+ var ansmap = new HashMap[Int, Int]
for i in ans do
var mp = i.split("=")
- var b = false
- if mp.last == "true" then b = true
var id = mp.first.split("_").last
+ var b = mp.last.to_i
if not id.is_numeric then continue
ansmap[id.to_i] = b
end
var p = new People(rname, rsurname)
for i in m.answers(db) do
if not ansmap.has_key(i.id) then
- p.answers[i] = false
+ p.answers[i] = 0
else
p.answers[i] = ansmap[i.id]
end
# Creates the tables and triggers for Opportunity (SQLite3 DB)
fun create_db do
- assert create_table("IF NOT EXISTS meetups (id CHAR(40) PRIMARY KEY, name TEXT, date TEXT, place TEXT);") else
+ assert create_table("IF NOT EXISTS meetups (id CHAR(40) PRIMARY KEY, name TEXT, date TEXT, place TEXT, answer_mode INTEGER DEFAULT 0);") else
print error or else "?"
end
assert create_table("IF NOT EXISTS people(id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, surname TEXT);") else
fun find_meetup_by_id(id: String): nullable Meetup do
var req = select("* FROM meetups where id={id.to_sql_string};")
for i in req do
- return new Meetup.from_db(i[0].to_s, i[1].to_s, i[2].to_s, i[3].to_s)
+ return new Meetup.from_db(i[0].to_s, i[1].to_s, i[2].to_s, i[3].to_s, i[4].to_i)
+ end
+ return null
+ end
+
+ # Find an `Answer` by its `id` or `null` if it could not be found
+ fun find_answer_by_id(id: Int): nullable Answer do
+ var req = select("* FROM answers WHERE id={id};")
+ for i in req do
+ return new Answer.from_db(i[0].to_i, i[2].to_s)
end
return null
end
# Change an Answer `ansid` for someone with an id `pid` to `resp`
#
# Returns `true` if the request was sucessful, false otherwise
- fun change_answer(pid: Int, ansid: Int, resp: Bool): Bool do
- var rsp = 0
- if resp then rsp = 1
- var rq = execute("INSERT OR REPLACE INTO part_answers(id_part, id_ans, value) VALUES({pid},{ansid},{rsp});")
- if not rq then
+ fun change_answer(pid: Int, ansid: Int, resp: Int): Bool do
+ var p = find_people_by_id(pid)
+ if p == null then
print "Error while updating answer {ansid}:{pid}"
- print error or else "Unknown error"
return false
end
- return true
+ var a = find_answer_by_id(ansid)
+ if a == null then
+ print "Error while updating answer {ansid}:{pid}"
+ return false
+ end
+ p.answers[a] = resp
+ if p.commit(self) then return true
+ return false
end
# Removes a person in the Database by its `id`
# Surname of the participant
var surname: String
# Map of the answers of a Meetup and the answers of the participant
- var answers: Map[Answer, Bool] = new HashMap[Answer, Bool]
+ # 0 = No
+ # 1 = Maybe
+ # 2 = Yes
+ var answers: Map[Answer, Int] = new HashMap[Answer, Int]
# To be used internally when fetching the `People` in Database
private init from_db(id: Int, name, surname: String) do
end
# Changes an answer `ans` (or adds it)
- fun answer=(ans: Answer, resp: Bool) do
+ fun answer=(ans: Answer, resp: Int) do
answers[ans] = resp
end
#
# NOTE: If `self` does not exist in the Database, no answers will be fetched
fun load_answers(db: OpportunityDB, meetup: Meetup) do
- self.answers = new HashMap[Answer, Bool]
- var req = db.select("answers.id, answers.name, part_answers.value FROM part_answers, answers WHERE part_answers.id_part={id} AND answers.id=part_answers.id_ans AND answers.meetup_id={meetup.id.to_sql_string} GROUP BY answers.id;")
+ self.answers = new HashMap[Answer, Int]
+ var req = db.select("answers.id, answers.name, part_answers.value FROM part_answers, answers WHERE part_answers.id_part={id} AND answers.id=part_answers.id_ans AND answers.meetup_id={meetup.id.html_escape.to_sql_string} GROUP BY answers.id;")
for i in req do
var ans = new Answer.from_db(i[0].to_i, i[1].to_s)
- answers[ans] = false
- if i[2].to_i == 1 then answers[ans] = true
+ answers[ans] = i[2].to_i
end
end
redef fun commit(db) do
if id == -1 then
- if not db.execute("INSERT INTO people (name,surname) VALUES ({name.to_sql_string}, {surname.to_sql_string});") then
+ if not db.execute("INSERT INTO people (name,surname) VALUES ({name.html_escape.to_sql_string}, {surname.html_escape.to_sql_string});") then
print "Error while adding people {self}"
print db.error or else "Unknown error"
return false
end
id = db.last_insert_rowid
else
- if not db.execute("UPDATE people SET name={name.to_sql_string}, surname={surname.to_sql_string} WHERE ID={id};") then
+ if not db.execute("UPDATE people SET name={name.html_escape.to_sql_string}, surname={surname.html_escape.to_sql_string} WHERE ID={id};") then
print "Error while updating people {self}"
print db.error or else "Unknown error"
return false
end
for i,j in answers do
if i.id == -1 then i.commit(db)
- var val = 0
- if j then val = 1
- if not db.execute("INSERT OR REPLACE INTO part_answers(id_part, id_ans, value) VALUES ({id},{i.id},{val});") then
- print("Error while adding/replacing part_answers {id}|{i.id}|{j}")
+ var val = j
+ var s = db.select("* FROM part_answers WHERE id_part={id} AND id_ans={i.id}")
+ if s != null and s.iterator.is_ok then
+ if not db.execute("UPDATE part_answers SET value={j} WHERE id_part={id} AND id_ans={i.id};") then
+ print "Error while updating part_answers {id}|{i.id} = {j}"
+ print db.error or else "Unknown error"
+ return false
+ end
+ continue
+ end
+ if not db.execute("INSERT INTO part_answers(id_part, id_ans, value) VALUES ({id},{i.id},{val});") then
+ print("Error while adding part_answers {id}|{i.id}|{j}")
print db.error or else "Unknown error"
return false
end
var date: String
# Place of the meetup
var place: String
+ # Mode of answering to the meetup (atm supports with or without Maybe)
+ var answer_mode: Int
# Builds the object with all the informations found in the database
- private init from_db(id, name, date, place: String) do
+ private init from_db(id, name, date, place: String, mode: Int) do
self.id = id
- self.name = name
- self.date = date
- self.place = place
+ init(name, date, place, mode)
end
# Gets the answers bound to the current `Meetup`
if id == "" then
var time = get_time
var tmpid = (name + date + place + time.to_s).sha1_to_s
- if not db.execute("INSERT INTO meetups (id, name, date, place) VALUES({tmpid.to_sql_string}, {name.to_sql_string}, {date.to_sql_string}, {place.to_sql_string});") then
+ 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"
return false
id = tmpid
return true
else
- return db.execute("UPDATE meetups (name, date, place) VALUES({name.to_sql_string}, {date.to_sql_string}, {place.to_sql_string}) WHERE ID={id.to_sql_string};")
+ return db.execute("UPDATE meetups SET name={name.html_escape.to_sql_string}, date={date.html_escape.to_sql_string}, place={place.html_escape.to_sql_string}, answer_mode={answer_mode} WHERE ID={id.to_sql_string};")
end
end
self.id = id
end
+ redef fun hash do
+ if id != -1 then return id
+ return super
+ end
+
# Loads the Meetup associated to `self`
#
# REQUIRE: is loaded in database
assert id != -1
var res = db.select("meetups.* FROM meetups, answers WHERE answers.id={id} AND answers.meetup_id=meetups.id;")
for i in res do
- return new Meetup.from_db(i[0].to_s, i[1].to_s, i[2].to_s, i[3].to_s)
+ return new Meetup.from_db(i[0].to_s, i[1].to_s, i[2].to_s, i[3].to_s, i[4].to_i)
end
# If no Meetup could be loaded, the contract was not respected
abort
end
+ # Counts the number of positive or maybe answers
+ fun count(db: OpportunityDB): Int do
+ if id == -1 then return -1
+ var count = 0
+ var res = db.select("part_answers.value FROM part_answers WHERE part_answers.id_ans={id};")
+ if meetup == null then meetup = load_meetup(db)
+ for i in res do
+ if meetup.answer_mode == 0 then
+ count += i[0].to_i
+ else
+ if i[0].to_i == 2 then count += 1
+ end
+ end
+ return count
+ end
+
+ # Counts the score for this particular answer
+ fun score(db: OpportunityDB): Int do
+ if id == -1 then return -1
+ var score = 0
+ var res = db.select("part_answers.value FROM part_answers WHERE part_answers.id_ans={id};")
+ for i in res do
+ score += i[0].to_i
+ end
+ return score
+ end
+
redef fun commit(db) do
var m = meetup
if m == null then return false
end
end
if id == -1 then
- if not db.execute("INSERT INTO answers (name, meetup_id) VALUES({name.to_sql_string}, {m.id.to_sql_string});") then
+ if not db.execute("INSERT INTO answers (name, meetup_id) VALUES({name.html_escape.to_sql_string}, {m.id.to_sql_string});") then
print "Cannot create {self} in database"
print db.error or else "Unknown error"
return false
end
id = db.last_insert_rowid
else
- if not db.execute("UPDATE answers (name) VALUES ({name.to_sql_string}) WHERE meetup_id={m.id.to_sql_string};") then
+ if not db.execute("UPDATE answers SET name=({name.html_escape.to_sql_string}) WHERE meetup_id={m.id.to_sql_string};") then
print "Error updating {self} in database"
print db.error or else "Unknown error"
return false
# Meetup the page is supposed to show
var meetup: nullable Meetup = null
+ # Answer mode for the meetup
+ var mode = 0
init from_id(id: String) do
var db = new OpportunityDB.open("opportunity")
meetup = db.find_meetup_by_id(id)
db.close
+ if meetup != null then mode = meetup.answer_mode
+ init
end
init do
- header.page_js = """
+ header.page_js = "mode = {mode};\n"
+ header.page_js += """
+ function update_scores(){
+ var anss = $('.answer');
+ var count = {};
+ var scores = {};
+ var answers = [];
+ var maxscore = 0;
+ for(i=0; i < anss.length; i++){
+ var incscore = 0;
+ var inccount = 0;
+ var idparts = anss[i].id.split("_");
+ var ansid = idparts[1];
+ var html = anss[i].innerHTML;
+ if(html === "<center>✔</center>"){
+ inccount = 1;
+ incscore = 2;
+ }else if(html === "<center>❓</center>"){
+ incscore = 1;
+ }
+ var intansid = parseInt(ansid)
+ if(answers.indexOf(intansid) == -1){
+ answers.push(intansid);
+ }
+ if(ansid in count){
+ count[ansid] += inccount;
+ }else{
+ count[ansid] = inccount;
+ }
+ if(ansid in scores){
+ scores[ansid] += incscore;
+ }else{
+ scores[ansid] = incscore;
+ }
+ if(scores[ansid] > maxscore){
+ maxscore = scores[ansid];
+ }
+ }
+ for(i=0; i < answers.length; i++){
+ var ansid = answers[i].toString();
+ var el = $('#total'+ansid)[0];
+ var ins = "<center>"+count[ansid];
+ if(scores[ansid] >= maxscore){
+ ins += "<br/><span style=\\"color:blue\\">★</span>";
+ }
+ ins += "</center>";
+ el.innerHTML = ins;
+ }
+ }
function change_answer(ele, id){
// modify only the currently selected entry
if (in_modification_id != id) return;
var e = document.getElementById(ele.id);
var i = e.innerHTML;
- var ans = true;
+ var ans = true;"""
+ if mode == 0 then
+ header.page_js += """
if(i === "<center>✔</center>"){
- ans = false;
+ ans = 0;
e.innerHTML = "<center>✘</center>"
e.style.color = "red";
}else{
+ ans = 1;
e.innerHTML = "<center>✔</center>";
e.style.color = "green";
- }
+ }"""
+
+ else
+ header.page_js += """
+ if(i === "<center>✔</center>"){
+ ans = 1;
+ e.innerHTML = "<center>❓</center>"
+ e.style.color = "#B8860B";
+ }else if(i === "<center>❓</center>"){
+ ans = 0;
+ e.innerHTML = "<center>✘</center>"
+ e.style.color = "red";
+ }else{
+ ans = 2;
+ e.innerHTML = "<center>✔</center>";
+ e.style.color = "green";
+ }"""
+ end
+ header.page_js += """
var a = ele.id.split('_')
var pid = a[1]
var aid = a[2]
+ update_scores();
$.ajax({
type: "POST",
url: "./rest/answer",
}
function change_temp_answer(ele){
var e = document.getElementById(ele.id);
- var i = e.innerHTML;
- var ans = true;
+ var i = e.innerHTML;"""
+ if mode == 0 then
+ header.page_js += """
+ if(i === "<center>✔</center>"){
+ e.innerHTML = "<center>✘</center>"
+ e.style.color = "red";
+ }else{
+ e.innerHTML = "<center>✔</center>";
+ e.style.color = "green";
+ }
+ """
+ else
+ header.page_js += """
if(i === "<center>✔</center>"){
- ans = false;
- e.innerHTML = "<center>✘</center>";
+ e.innerHTML = "<center>❓</center>";
+ e.style.color = "#B8860B";
+ }else if(i === "<center>❓</center>"){
+ e.innerHTML = "<center>✘</center>"
e.style.color = "red";
}else{
e.innerHTML = "<center>✔</center>";
e.style.color = "green";
}
+ """
+ end
+ header.page_js += """
+ update_scores();
}
function add_part(ele){
var e = document.getElementById(ele.id);
ansmap = {};
for(i=0;i<ans.length;i++){
var curr = ans.eq(i)
+ """
+ if mode == 0 then
+ header.page_js += """
if(curr[0].innerHTML === "<center>✔</center>"){
- ansmap[curr.attr('id')] = true
+ ansmap[curr.attr('id')] = 1
}else{
- ansmap[curr.attr('id')] = false
- }
+ ansmap[curr.attr('id')] = 0
+ }"""
+ else
+ header.page_js += """
+ if(curr[0].innerHTML === "<center>✔</center>"){
+ ansmap[curr.attr('id')] = 2
+ }else if(curr[0].innerHTML === "<center>❓</center>"){
+ ansmap[curr.attr('id')] = 1
+ }else{
+ ansmap[curr.attr('id')] = 0
+ }"""
+ end
+ header.page_js += """
}
$.ajax({
type: "POST",
var arr = ele.id.split("_")
var pid = arr[1]
$('#' + ele.id).parent().parent().parent().remove();
+ update_scores();
$.ajax({
type: "POST",
url: "./rest/people",
}
});
}
-
// ID of line currently open for modification
var in_modification_id = null;
function modify_people(ele, id){
t.add "<td>"
t.add i.to_s
t.add "</td>"
- for j,k in i.answers do
+ for j, k in i.answers do
var color
- if k then
- color = "green"
- else color = "red"
-
+ if answer_mode == 0 then
+ if k == 1 then
+ color = "green"
+ else
+ color = "red"
+ end
+ else
+ if k == 2 then
+ color = "green"
+ else if k == 1 then
+ color = "#B8860B"
+ else
+ color = "red"
+ end
+ end
t.add """<td class="answer" onclick="change_answer(this, {{{i.id}}})" id="answer_{{{j.id}}}_{{{i.id}}}" style="color:{{{color}}}">"""
t.add "<center>"
- if k then
- t.add "✔"
+ if answer_mode == 0 then
+ if k == 1 then
+ t.add "✔"
+ else
+ t.add "✘"
+ end
else
- t.add "✘"
+ if k == 2 then
+ t.add "✔"
+ else if k == 1 then
+ t.add "❓"
+ else
+ t.add "✘"
+ end
end
t.add "</center></td>"
end
t.add """
<td><center><span id="add_{{{id}}}" onclick="add_part(this)" style="color:green;" class="action"><button class="btn btn-xs btn-success" type="button">Done</button></span></center></td>"""
t.add "</tr>"
+ # Compute score for each answer
+ var scores = new HashMap[Int, Int]
+ var maxsc = 0
+ for i in answers(db) do
+ scores[i.id] = i.score(db)
+ if scores[i.id] > maxsc then maxsc = scores[i.id]
+ end
+ t.add """
+<tr id="total">
+ <th>Total</th>
+ """
+ for i in answers(db) do
+ t.add """<th id="total{{{i.id}}}"><center>{{{i.count(db)}}}"""
+ if scores.has_key(i.id) and scores[i.id] >= maxsc then
+ t.add """<br/><span style="color:blue">★</span>"""
+ end
+ t.add "</center></th>"
+ end
+ t.add "</th>"
+ t.add """
+ <th></th>
+</tr>"""
t.add "</table>"
t.add "</div>"
return t
<input name="meetup_place" id="meetup_place" type="text" class="form-control" placeholder="Place of the event" value="{{{if meet != null then meet.place else ""}}}">
</div>
</div>
+ <div class = "form-group">
+ <label for="meetup=maybe" class="col-sm-4 control-label">Add a Maybe option?</label>
+ <div class="col-sm-8">
+ <input name="meetup_mode" id="meetup_mode" type="checkbox" class="form-control">
+ </div>
+ </div>
<h2>Opportunities</h2>
<div id="answers">
"""
var hj = new People("Jack", "Handsome")
-var m = new Meetup("Awaken the warrior", "2024/05/28", "Vault of the Warrior")
+var m = new Meetup("Awaken the warrior", "2024/05/28", "Vault of the Warrior", 0)
assert m.commit(db)
var vh = new People("Hunter", "Vault")
h.meetup = m
h.commit(db)
-hj.answer(y) = true
-hj.answer(n) = false
-hj.answer(h) = false
+hj.answer(y) = 1
+hj.answer(n) = 0
+hj.answer(h) = 0
-vh.answer(y) = true
-vh.answer(n) = false
-vh.answer(h) = false
+vh.answer(y) = 1
+vh.answer(n) = 0
+vh.answer(h) = 0
-ll.answer(y) = true
-ll.answer(n) = false
-ll.answer(h) = true
+ll.answer(y) = 1
+ll.answer(n) = 0
+ll.answer(h) = 1
hj.commit db
vh.commit db
module ab
var words = gets.split(" ")
+if words.length != 2 then
+ print "Expected two numbers"
+ return
+end
print words[0].to_i + words[1].to_i
fun headless_run
do
+ srand_from 0
print "Headless run"
# Only run the playscene
var scene = new PlayScene(80000,60000)
# ~~~
module a_star
-redef class Object
- protected fun debug_a_star: Bool do return false
- private fun debug(msg: String) do if debug_a_star then
- sys.stderr.write "a_star debug: {msg}\n"
- end
-end
-
# General graph node
class Node
type N: Node
var current_bucket = buckets[cost % nbr_buckets]
if current_bucket.is_empty then # move to next bucket
- debug "b {cost} {cost % nbr_buckets} {buckets[cost % nbr_buckets].hash}"
cost += 1
if cost > max_cost then return null
bucket_searched += 1
if bucket_searched > nbr_buckets then break
else # found a node
- debug "c {cost}"
frontier_node = current_bucket.pop
if frontier_node.open then break
# at destination
else if frontier_node == destination or
(alt_targets != null and alt_targets.accept(frontier_node)) then
- debug "picked {frontier_node}, is destination"
var path = new Path[N](cost)
else
frontier_node.open = false
- debug "w exploring adjacents of {frontier_node}"
-
for link in frontier_node.links do
var peek_node = link.to
- debug "v {context.is_blocked(link)} {peek_node.last_pathfinding_evocation != graph.pathfinding_current_evocation} {peek_node.best_cost_up_to > frontier_node.best_cost_up_to + context.cost(link)}, {peek_node.best_cost_up_to} > {frontier_node.best_cost_up_to} + {context.cost(link)}"
if not context.is_blocked(link) and
(peek_node.last_pathfinding_evocation != graph.pathfinding_current_evocation or
(peek_node.open and
var at_bucket = buckets[est_cost % nbr_buckets]
at_bucket.add(peek_node)
-
- debug "u putting {peek_node} at {est_cost} -> {est_cost % nbr_buckets} {at_bucket.hash}, {cost}+{context.cost(link)}"
end
end
end
new_annotation max_api_version
new_annotation target_api_version
new_annotation android_manifest
+ new_annotation android_manifest_application
+ new_annotation android_manifest_activity
end
import java
fun [](key: String): nullable Object is abstract
# Store `value` at `key`
- fun []=(key: String, value: Serializable) is abstract
+ fun []=(key: String, value: nullable Serializable) is abstract
end
var current_bucket = buckets[current_bucket_key]
var next_bucket = new HashSet[Bucketable[G]]
+ buckets[current_bucket_key] = next_bucket
+ self.next_bucket = next_bucket
for e in current_bucket do
var act_at = e.act_at
end
end
end
-
- self.next_bucket = next_bucket
- buckets[current_bucket_key] = next_bucket
end
end
# A counter counts occurrences of things
# Use this instead of a `HashMap[E, Int]`
+#
+# ~~~
+# var c = new Counter[String].from(["a", "a", "b", "b", "b", "c"])
+# assert c["a"] == 2
+# assert c["b"] == 3
+# assert c["c"] == 1
+# assert c["d"] == 0
+# ~~~
+#
+# The counter class can also be used to gather statistical informations.
+#
+# ~~~~
+# assert c.length == 3 # because 3 distinct values
+# assert c.max == "b" # because "b" has the most count (3)
+# assert c.avg == 2.0 # because it is the mean of the counts
+# ~~~~
class Counter[E: Object]
super Map[E, Int]
# Total number of counted occurrences
+ #
+ # ~~~
+ # var c = new Counter[String]
+ # assert c.sum == 0
+ # c.inc_all(["a", "a", "b", "b", "b", "c"])
+ # assert c.sum == 6
+ # ~~~
var sum: Int = 0
private var map = new HashMap[E, Int]
sum += 1
end
+ # Count one more for each element of `es`
+ fun inc_all(es: Collection[E])
+ do
+ for e in es do inc(e)
+ end
+
+ # A new Counter initialized with `inc_all`.
+ init from(es: Collection[E])
+ do
+ inc_all(es)
+ end
+
# Return an array of elements sorted by occurrences
+ #
+ # ~~~
+ # var c = new Counter[String].from(["a", "a", "b", "b", "b", "c"])
+ # assert c.sort == ["c", "a", "b"]
+ # ~~~
fun sort: Array[E]
do
var res = map.keys.to_a
# @toimplement by default just call `to_s` on the element
protected fun element_to_s(e: E): String
do
- do return e.to_s
+ return e.to_s
end
# Display statistical information
end
end
- # Return the element with the highest value
+ # Return the element with the highest value (aka. the mode)
+ #
+ # ~~~
+ # var c = new Counter[String].from(["a", "a", "b", "b", "b", "c"])
+ # assert c.max == "b"
+ # ~~~
+ #
+ # If more than one max exists, the first one is returned.
fun max: nullable E do
var max: nullable Int = null
var elem: nullable E = null
end
# Return the couple with the lowest value
+ #
+ # ~~~
+ # var c = new Counter[String].from(["a", "a", "b", "b", "b", "c"])
+ # assert c.min == "c"
+ # ~~~
+ #
+ # If more than one min exists, the first one is returned.
fun min: nullable E do
var min: nullable Int = null
var elem: nullable E = null
return elem
end
- # Values average
+ # Values average (aka. arithmetic mean)
+ #
+ # ~~~
+ # var c = new Counter[String].from(["a", "a", "b", "b", "b", "c"])
+ # assert c.avg == 2.0
+ # ~~~
fun avg: Float do
if values.is_empty then return 0.0
return (sum / values.length).to_f
end
# The standard derivation of the counter values
+ #
+ # ~~~
+ # var c = new Counter[String].from(["a", "a", "b", "b", "b", "c"])
+ # assert c.std_dev > 0.81
+ # assert c.std_dev < 0.82
+ # ~~~
fun std_dev: Float do
var avg = self.avg
var sum = 0.0
class DummyArray
super Set[Int]
- super ArrayCapable[Int]
private var capacity: Int
redef var length: Int
private var keys: NativeArray[Int]
init(capacity: Int)
do
_capacity = capacity
- _keys = calloc_array(capacity)
- _values = calloc_array(capacity)
+ _keys = new NativeArray[Int](capacity)
+ _values = new NativeArray[Int](capacity)
end
end
# Get the requested URI, and check the HTTP response. Then convert to JSON
# and check for Github errors.
- fun get_and_check(uri: String): nullable Object
+ fun get_and_check(uri: String): nullable Jsonable
do
var request = new CurlHTTPRequest(uri, self)
request.user_agent = user_agent
var response = request.execute
if response isa CurlResponseSuccess then
- var obj = response.body_str.json_to_nit_object
- if obj isa HashMap[String, nullable Object] then
+ var obj = response.body_str.parse_json
+ if obj isa JsonObject then
if obj.keys.has("message") then
print "Message from Github API: {obj["message"] or else ""}"
print "Requested URI: {uri}"
super
end
-redef class HashCollection[K,N]
+redef class HashCollection[K]
redef fun node_at_idx(i,k)
do
sys.gt_count += 1
# most of JNI functions. You can use it to further customize the behavior
# of your code.
module java is
- c_compiler_option("-I $(JAVA_HOME)/include/")
+ c_compiler_option "-I $(JAVA_HOME)/include/ -I $(JAVA_HOME)/include/linux/"
c_linker_option("-L $(JNI_LIB_PATH) -ljvm")
new_annotation extra_java_files
end
# to get the underlying Json data. It can also be used as any Json types.
module dynamic
+import error
private import static
-import standard
class JsonValue
var value: nullable Object
#
# assert """{"a": 123}""".to_json_value.is_map
# assert not "123".to_json_value.is_map
- fun is_map: Bool do return value isa HashMap[String, nullable Object]
+ fun is_map: Bool do return value isa MapRead[String, nullable Object]
# Get this value as a `Map[String, JsonValue]`
#
# require: `self.is_map`
fun to_map: Map[String, JsonValue] do
var value = value
- assert value isa HashMap[String, nullable Object]
+ assert value isa MapRead[String, nullable Object]
var map = new HashMap[String, JsonValue]
for k, v in value do map[k] = new JsonValue(v)
# assert "[1, 2, 3, 4, 5]".to_json_value.is_array
# assert "[null, true, false, 0.0, 1, \"str\"]".to_json_value.is_array
# assert """["a", "b", "c"]""".to_json_value.is_array
- fun is_array: Bool do return value isa Array[nullable Object]
+ fun is_array: Bool do return value isa SequenceRead[nullable Object]
# Get this value as an `Array[JsonValue]`
#
fun to_a: Array[JsonValue]
do
var value = value
- assert value isa Array[nullable Object]
+ assert value isa SequenceRead[nullable Object]
var a = new Array[JsonValue]
for e in value do a.add(new JsonValue(e))
return a
end
+ ### Error
+
+ # Is this value an error?
+ #
+ # assert "[]".to_json_value[0].is_error
+ # assert "[".to_json_value.is_error
+ # assert not "[]".to_json_value.is_error
+ fun is_error: Bool do return value isa Error
+
+ # Get this value as a `Error`.
+ #
+ # require: `self.is_error`
+ fun to_error: Error do return value.as(Error)
+
+ ### JsonParseError
+
+ # Is this value a parse error?
+ #
+ # assert "[".to_json_value.is_parse_error
+ # assert not "[]".to_json_value.is_parse_error
+ fun is_parse_error: Bool do return value isa JsonParseError
+
+ # Get this value as a `JsonParseError`.
+ #
+ # require: `self.is_parse_error`
+ fun to_parse_error: JsonParseError do return value.as(JsonParseError)
+
+ ### Children access
+
# Iterator over the values of the array `self`
#
# require: `self.is_array`
# assert """{"a": 123}""".to_json_value["a"].to_i == 123
# assert """{"123": "a"}""".to_json_value[123].to_s == "a"
# assert """{"John Smith": 1980}""".to_json_value[["John ", "Smith"]].to_i == 1980
+ # assert """{"a": 123}""".to_json_value["b"].is_error
#
# assert """["a", "b", "c"]""".to_json_value[0].to_s == "a"
- fun [](key: Object): JsonValue
- do
+ # assert """["a", "b", "c"]""".to_json_value[3].is_error
+ fun [](key: Object): JsonValue do
var value = value
- if value isa HashMap[String, nullable Object] then
- return new JsonValue(value[key.to_s])
- else if value isa Array[nullable Object] then
- assert key isa Int
- return new JsonValue(value[key])
- else abort
+ var result: nullable Object
+ if is_error then
+ return self
+ else if value isa MapRead[String, nullable Object] then
+ key = key.to_s
+ if value.has_key(key) then
+ result = value[key]
+ else
+ result = new JsonKeyError("Key `{key}` not found.", self, key)
+ end
+ else if value isa SequenceRead[nullable Object] then
+ if key isa Int then
+ if key < value.length and key >= 0 then
+ result = value[key]
+ else
+ result = new JsonKeyError("Index `{key}` out of bounds.",
+ self, key)
+ end
+ else
+ result = new JsonKeyError("Invalid key type. Expecting `Int`. Got `{key.class_name}`.",
+ self, key)
+ end
+ else
+ result = new JsonKeyError("Invalid `[]` access on a `{json_type}` JsonValue.",
+ self, key)
+ end
+ return new JsonValue(result)
end
# Advanced query to get a value within the map `self` or it's children.
# assert """{"a": {"t": true, "f": false}}""".to_json_value.get("a").is_map
# assert """{"a": {"t": true, "f": false}}""".to_json_value.get("a.t").to_bool
# assert not """{"a": {"t": true, "f": false}}""".to_json_value.get("a.f").to_bool
+ # assert """{"a": {"t": true, "f": false}}""".to_json_value.get("a.t.t").is_error
# assert """{"a": {"b": {"c": {"d": 123}}}}""".to_json_value.get("a.b.c.d").to_i == 123
- fun get(query: String): JsonValue
- do
+ # assert """{"a": {"b": {"c": {"d": 123}}}}""".to_json_value.get("a.z.c.d").is_error
+ fun get(query: String): JsonValue do
var keys = query.split(".")
var value = value
- for key in keys do
- assert value isa HashMap[String, nullable Object]
- value = value[key]
+ if is_error then return self
+ for i in [0..keys.length[ do
+ var key = keys[i]
+ if value isa MapRead[String, nullable Object] then
+ if value.has_key(key) then
+ value = value[key]
+ else
+ var sub_query = sub_query_to_s(keys, i)
+ var e = new JsonKeyError("Key `{key}` not found.",
+ self, sub_query)
+ return new JsonValue(e)
+ end
+ else
+ var sub_query = sub_query_to_s(keys, i)
+ var val_type = (new JsonValue(value)).json_type
+ var e = new JsonKeyError("Value at `{sub_query}` is not a map. Got type `{val_type}`",
+ self, sub_query)
+ return new JsonValue(e)
+ end
end
return new JsonValue(value)
end
+
+ # Concatenate all keys up to `last` for debugging purposes.
+ #
+ # Note: This method deletes elements in `keys`.
+ private fun sub_query_to_s(keys: Array[String], last: Int): String do
+ last += 1
+ for j in [last..keys.length[ do keys.pop
+ return keys.join(".")
+ end
+
+ # Return a human-readable description of the type.
+ #
+ # For debugging purpose only.
+ fun json_type: String do
+ if is_array then return "array"
+ if is_bool then return "bool"
+ if is_float then return "float"
+ if is_int then return "int"
+ if is_null then return "null"
+ if is_map then return "map"
+ if is_string then return "string"
+ if is_parse_error then return "parse_error"
+ if is_error then return "error"
+ return "undefined"
+ end
end
-redef class String
+# Keyed access failed.
+class JsonKeyError
+ super Error
+
+ # The value on which the access was requested.
+ var json_value: JsonValue
+
+ # The requested key.
+ #
+ # In the case of `JsonValue.get`, the sub-query that failed.
+ var key: Object
+end
+
+redef class Text
# Parse `self` to obtain a `JsonValue`
- fun to_json_value: JsonValue
- do
- var value = json_to_nit_object
+ fun to_json_value: JsonValue do
+ var value = parse_json
return new JsonValue(value)
end
end
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# This file is free software, which comes along with NIT. This software is
+# distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+# without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE. You can modify it is you want, provided this header
+# is kept unaltered, and a notification of the changes is added.
+# You are allowed to redistribute it and sell it, alone or is a part of
+# another product.
+
+# Errors related to JSON parsing.
+module json::error
+
+import nitcc_runtime
+
+# Ill-formed JSON.
+class JsonParseError
+ super Error
+
+ # The location of the error in the original text.
+ var position: nullable Position
+
+ redef fun to_s do
+ var p = position
+ if p isa Position then
+ return "[{p}] {super}"
+ else
+ return super
+ end
+ end
+end
# This file is part of NIT ( http://www.nitlanguage.org ).
#
# Copyright 2014 Alexis Laferrière <alexis.laf@xymus.net>
+# Copyright 2014 Jean-Christophe Beaupré <jcbrinfo@users.noreply.github.com>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# See the License for the specific language governing permissions and
# limitations under the License.
-# Offers two APIs to manipulate read Json strings.
+# Provides two APIs to manipulate JSON strings.
+#
+# Both `dynamic` and `static` modules provide at least a method to parse a
+# value written in JSON, but only `static` provide a method to translate a
+# value into JSON.
#
# The `dynamic` module provides a simple interface to get information
-# from a Json document. You must be careful as all services are provided on
+# from a JSON document. You must be careful as all services are provided on
# each nodes and a wrongful use can `abort`.
#
-# The `static` module converts a Json string to a nullable Nit object. The object
-# must then be type checked before it can be used.
+# The `static` module provides a common interface for anything that can be
+# translated into a JSON document. The provided parsing method return a
+# nullable Nit object that must then be type-checked before it can be used.
module json
import static
private fun dfastate_28: DFAState28 do return once new DFAState28
private fun dfastate_29: DFAState29 do return once new DFAState29
private fun dfastate_30: DFAState30 do return once new DFAState30
+ private fun dfastate_31: DFAState31 do return once new DFAState31
+ private fun dfastate_32: DFAState32 do return once new DFAState32
+ private fun dfastate_33: DFAState33 do return once new DFAState33
+ private fun dfastate_34: DFAState34 do return once new DFAState34
end
class MyNToken
super NToken
super DFAState
redef fun trans(char) do
var c = char.ascii
- return dfastate_2
+ if c <= 33 then return null
+ if c <= 34 then return dfastate_2
+ if c <= 46 then return null
+ if c <= 47 then return dfastate_2
+ if c <= 91 then return null
+ if c <= 92 then return dfastate_2
+ if c <= 97 then return null
+ if c <= 98 then return dfastate_2
+ if c <= 101 then return null
+ if c <= 102 then return dfastate_2
+ if c <= 109 then return null
+ if c <= 110 then return dfastate_2
+ if c <= 113 then return null
+ if c <= 114 then return dfastate_2
+ if c <= 115 then return null
+ if c <= 116 then return dfastate_2
+ if c <= 117 then return dfastate_31
+ return null
+ end
+end
+private class DFAState31
+ super DFAState
+ redef fun trans(char) do
+ var c = char.ascii
+ if c <= 47 then return null
+ if c <= 57 then return dfastate_32
+ if c <= 64 then return null
+ if c <= 90 then return dfastate_32
+ if c <= 96 then return null
+ if c <= 122 then return dfastate_32
+ return null
+ end
+end
+private class DFAState32
+ super DFAState
+ redef fun trans(char) do
+ var c = char.ascii
+ if c <= 47 then return null
+ if c <= 57 then return dfastate_33
+ if c <= 64 then return null
+ if c <= 90 then return dfastate_33
+ if c <= 96 then return null
+ if c <= 122 then return dfastate_33
+ return null
+ end
+end
+private class DFAState33
+ super DFAState
+ redef fun trans(char) do
+ var c = char.ascii
+ if c <= 47 then return null
+ if c <= 57 then return dfastate_34
+ if c <= 64 then return null
+ if c <= 90 then return dfastate_34
+ if c <= 96 then return null
+ if c <= 122 then return dfastate_34
+ return null
+ end
+end
+private class DFAState34
+ super DFAState
+ redef fun trans(char) do
+ var c = char.ascii
+ if c <= 47 then return null
+ if c <= 57 then return dfastate_2
+ if c <= 64 then return null
+ if c <= 90 then return dfastate_2
+ if c <= 96 then return null
+ if c <= 122 then return dfastate_2
+ return null
end
end
# This file is part of NIT ( http://www.nitlanguage.org ).
#
# Copyright 2014 Alexis Laferrière <alexis.laf@xymus.net>
+# Copyright 2014 Alexandre Terrasa <alexandre@moz-concept.com>
+# Copyright 2014 Jean-Christophe Beaupré <jcbrinfo@users.noreply.github.com>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# Static interface to get Nit objects from a Json string.
#
-# `String::json_to_nit_object` returns an equivalent Nit object from
+# `Text::parse_json` returns an equivalent Nit object from
# the Json source. This object can then be type checked by the usual
# languages features (`isa` and `as`).
module static
-import standard
+import error
private import json_parser
private import json_lexer
+# Something that can be translated to JSON.
+interface Jsonable
+ # Encode `self` in JSON.
+ #
+ # SEE: `append_json`
+ fun to_json: String is abstract
+
+ # Append the JSON representation of `self` to the specified buffer.
+ #
+ # SEE: `to_json`
+ fun append_json(buffer: Buffer) do
+ buffer.append(to_json)
+ end
+end
+
+redef class Text
+ super Jsonable
+
+ redef fun append_json(buffer) do
+ buffer.add '\"'
+ for i in [0..self.length[ do
+ var char = self[i]
+ if char == '\\' then
+ buffer.append "\\\\"
+ else if char == '\"' then
+ buffer.append "\\\""
+ else if char == '\/' then
+ buffer.append "\\/"
+ else if char < 16.ascii then
+ if char == '\n' then
+ buffer.append "\\n"
+ else if char == '\r' then
+ buffer.append "\\r"
+ else if char == '\t' then
+ buffer.append "\\t"
+ else if char == 0x0C.ascii then
+ buffer.append "\\f"
+ else if char == 0x08.ascii then
+ buffer.append "\\b"
+ else
+ buffer.append "\\u000{char.ascii.to_hex}"
+ end
+ else if char < ' ' then
+ buffer.append "\\u00{char.ascii.to_hex}"
+ else
+ buffer.add char
+ end
+ end
+ buffer.add '\"'
+ end
+
+ # Encode `self` in JSON.
+ #
+ # assert "\t\"http://example.com\"\r\n\0\\".to_json ==
+ # "\"\\t\\\"http:\\/\\/example.com\\\"\\r\\n\\u0000\\\\\""
+ redef fun to_json do
+ var buffer = new FlatBuffer
+ append_json(buffer)
+ return buffer.write_to_string
+ end
+
+ # Parse `self` as JSON.
+ #
+ # If `self` is not a valid JSON document or contains an unsupported escape
+ # sequence, return a `JSONParseError`.
+ #
+ # Example with `JsonObject`:
+ #
+ # var obj = "\{\"foo\": \{\"bar\": true, \"goo\": [1, 2, 3]\}\}".parse_json
+ # assert obj isa JsonObject
+ # assert obj["foo"] isa JsonObject
+ # assert obj["foo"].as(JsonObject)["bar"] == true
+ #
+ # Example with `JsonArray`:
+ #
+ # var arr = "[1, 2, 3]".parse_json
+ # assert arr isa JsonArray
+ # assert arr.length == 3
+ # assert arr.first == 1
+ # assert arr.last == 3
+ #
+ # Example with `String`:
+ #
+ # var str = "\"foo, bar, baz\"".parse_json
+ # assert str isa String
+ # assert str == "foo, bar, baz"
+ #
+ # Example of a syntaxic error:
+ #
+ # var bad = "\{foo: \"bar\"\}".parse_json
+ # assert bad isa JsonParseError
+ # assert bad.position.col_start == 2
+ fun parse_json: nullable Jsonable do
+ var lexer = new Lexer_json(to_s)
+ var parser = new Parser_json
+ var tokens = lexer.lex
+ parser.tokens.add_all(tokens)
+ var root_node = parser.parse
+ if root_node isa NStart then
+ return root_node.n_0.to_nit_object
+ else if root_node isa NError then
+ return new JsonParseError(root_node.message, root_node.position)
+ else abort
+ end
+end
+
+redef class Buffer
+
+ # Append the JSON representation of `jsonable` to `self`.
+ #
+ # Append `"null"` for `null`.
+ private fun append_json_of(jsonable: nullable Jsonable) do
+ if jsonable isa Jsonable then
+ append jsonable.to_json
+ else
+ append "null"
+ end
+ end
+end
+
+redef class Int
+ super Jsonable
+
+ # Encode `self` in JSON.
+ #
+ # assert 0.to_json == "0"
+ # assert (-42).to_json == "-42"
+ redef fun to_json do return self.to_s
+end
+
+redef class Float
+ super Jsonable
+
+ # Encode `self` in JSON.
+ #
+ # Note: Because this method use `to_s`, it may lose precision.
+ #
+ # ~~~
+ # # Will not work as expected.
+ # # assert (-0.0).to_json == "-0.0"
+ #
+ # assert (.5).to_json == "0.5"
+ # assert (0.0).to_json == "0.0"
+ # ~~~
+ redef fun to_json do return self.to_s
+end
+
+redef class Bool
+ super Jsonable
+
+ # Encode `self` in JSON.
+ #
+ # assert true.to_json == "true"
+ # assert false.to_json == "false"
+ redef fun to_json do return self.to_s
+end
+
+# A map that can be translated into a JSON object.
+interface JsonMapRead[K: String, V: nullable Jsonable]
+ super MapRead[K, V]
+ super Jsonable
+
+ redef fun append_json(buffer) do
+ buffer.append "\{"
+ var it = iterator
+ if it.is_ok then
+ append_json_entry(it, buffer)
+ while it.is_ok do
+ buffer.append ","
+ append_json_entry(it, buffer)
+ end
+ end
+ it.finish
+ buffer.append "\}"
+ end
+
+ # Encode `self` in JSON.
+ #
+ # var obj = new JsonObject
+ # obj["foo"] = "bar"
+ # assert obj.to_json == "\{\"foo\":\"bar\"\}"
+ # obj = new JsonObject
+ # obj["baz"] = null
+ # assert obj.to_json == "\{\"baz\":null\}"
+ redef fun to_json do
+ var buffer = new FlatBuffer
+ append_json(buffer)
+ return buffer.write_to_string
+ end
+
+ private fun append_json_entry(iterator: MapIterator[String, nullable Jsonable],
+ buffer: Buffer) do
+ buffer.append iterator.key.to_json
+ buffer.append ":"
+ buffer.append_json_of(iterator.item)
+ iterator.next
+ end
+end
+
+# A JSON Object.
+class JsonObject
+ super JsonMapRead[String, nullable Jsonable]
+ super HashMap[String, nullable Jsonable]
+end
+
+# A sequence that can be translated into a JSON array.
+class JsonSequenceRead[E: nullable Jsonable]
+ super Jsonable
+ super SequenceRead[E]
+
+ redef fun append_json(buffer) do
+ buffer.append "["
+ var it = iterator
+ if it.is_ok then
+ append_json_entry(it, buffer)
+ while it.is_ok do
+ buffer.append ","
+ append_json_entry(it, buffer)
+ end
+ end
+ it.finish
+ buffer.append "]"
+ end
+
+ # Encode `self` in JSON.
+ #
+ # var arr = new JsonArray.with_items("foo", null)
+ # assert arr.to_json == "[\"foo\",null]"
+ # arr.pop
+ # assert arr.to_json =="[\"foo\"]"
+ # arr.pop
+ # assert arr.to_json =="[]"
+ redef fun to_json do
+ var buffer = new FlatBuffer
+ append_json(buffer)
+ return buffer.write_to_string
+ end
+
+ private fun append_json_entry(iterator: Iterator[nullable Jsonable],
+ buffer: Buffer) do
+ buffer.append_json_of(iterator.item)
+ iterator.next
+ end
+end
+
+# A JSON array.
+class JsonArray
+ super JsonSequenceRead[nullable Jsonable]
+ super Array[nullable Jsonable]
+end
+
+redef class JsonParseError
+ super Jsonable
+
+ # Get the JSON representation of `self`.
+ #
+ # var err = new JsonParseError("foo", new Position(1, 2, 3, 4, 5, 6))
+ # assert err.to_json == "\{\"error\":\"JsonParseError\"," +
+ # "\"position\":\{" +
+ # "\"pos_start\":1,\"pos_end\":2," +
+ # "\"line_start\":3,\"line_end\":4," +
+ # "\"col_start\":5,\"col_end\":6" +
+ # "\},\"message\":\"foo\"\}"
+ redef fun to_json do
+ return "\{\"error\":\"JsonParseError\"," +
+ "\"position\":{position.to_json}," +
+ "\"message\":{message.to_json}\}"
+ end
+end
+
+redef class Position
+ super Jsonable
+
+ # Get the JSON representation of `self`.
+ #
+ # var pos = new Position(1, 2, 3, 4, 5, 6)
+ # assert pos.to_json == "\{" +
+ # "\"pos_start\":1,\"pos_end\":2," +
+ # "\"line_start\":3,\"line_end\":4," +
+ # "\"col_start\":5,\"col_end\":6" +
+ # "\}"
+ redef fun to_json do
+ return "\{\"pos_start\":{pos_start},\"pos_end\":{pos_end}," +
+ "\"line_start\":{line_start},\"line_end\":{line_end}," +
+ "\"col_start\":{col_start},\"col_end\":{col_end}\}"
+ end
+end
+
+################################################################################
+# Redef parser
+
redef class Nvalue
- fun to_nit_object: nullable Object is abstract
+ fun to_nit_object: nullable Jsonable is abstract
end
redef class Nvalue_number
end
redef class Nstring
- # FIXME support \n, etc.
- fun to_nit_string: String do return text.substring(1, text.length-2).
- replace("\\\\", "\\").replace("\\\"", "\"").replace("\\b", "\b").
- replace("\\/", "/").replace("\\n", "\n").replace("\\r", "\r").
- replace("\\t", "\t")
+ fun to_nit_string: String do
+ var res = new FlatBuffer
+ var i = 1
+ while i < text.length - 1 do
+ var char = text[i]
+ if char == '\\' then
+ i += 1
+ char = text[i]
+ if char == 'b' then
+ char = 0x08.ascii
+ else if char == 'f' then
+ char = 0x0C.ascii
+ else if char == 'n' then
+ char = '\n'
+ else if char == 'r' then
+ char = '\r'
+ else if char == 't' then
+ char = '\t'
+ else if char == 'u' then
+ var code = text.substring(i + 1, 4).to_hex
+ # TODO UTF-16 escaping is not supported yet.
+ if code >= 128 then
+ char = '?'
+ else
+ char = code.ascii
+ end
+ i += 4
+ end
+ # `"`, `/` or `\` => Keep `char` as-is.
+ end
+ res.add char
+ i += 1
+ end
+ return res.write_to_string
+ end
end
redef class Nvalue_object
- redef fun to_nit_object
- do
- var obj = new HashMap[String, nullable Object]
+ redef fun to_nit_object do
+ var obj = new JsonObject
var members = n_members
if members != null then
var pairs = members.pairs
redef class Npair
fun name: String do return n_string.to_nit_string
- fun value: nullable Object do return n_value.to_nit_object
+ fun value: nullable Jsonable do return n_value.to_nit_object
end
redef class Nvalue_array
redef fun to_nit_object
do
- var arr = new Array[nullable Object]
+ var arr = new JsonArray
var elements = n_elements
if elements != null then
var items = elements.items
redef class Nelements_head
redef fun items do return [n_value]
end
-
-redef class Text
- fun json_to_nit_object: nullable Object
- do
- var lexer = new Lexer_json(to_s)
- var parser = new Parser_json
- var tokens = lexer.lex
- parser.tokens.add_all(tokens)
- var root_node = parser.parse
- if root_node isa NStart then
- return root_node.n_0.to_nit_object
- else if root_node isa NLexerError then
- var pos = root_node.position
- print "Json lexer error: {root_node.message} at {pos or else "<unknown>"} for {root_node}"
- return null
- else if root_node isa NParserError then
- var pos = root_node.position
- print "Json parsing error: {root_node.message} at {pos or else "<unknown>"} for {root_node}"
- return null
- else abort
- end
-end
class JsonDeserializer
super Deserializer
- var root: nullable Object
- var path = new Array[HashMap[String, nullable Object]]
+ var root: nullable Jsonable
+ var path = new Array[JsonObject]
var id_to_object = new HashMap[Int, Object]
var just_opened_id: nullable Int = null
init(text: Text)
do
- var root = text.json_to_nit_object
- if root isa HashMap[String, nullable Object] then path.add(root)
+ var root = text.parse_json
+ if root isa JsonObject then path.add(root)
self.root = root
end
# Convert from simple Json object to Nit object
private fun convert_object(object: nullable Object): nullable Object
do
- if object isa HashMap[String, nullable Object] then
+ if object isa JsonObject then
assert object.keys.has("__kind")
var kind = object["__kind"]
end
redef class Char
- redef fun serialize_to_json(v) do v.stream.write "\{\"__kind\": \"char\", \"__val\": \"{to_s.to_json_s}\"\}"
+ redef fun serialize_to_json(v) do v.stream.write "\{\"__kind\": \"char\", \"__val\": {to_s.to_json}\}"
end
redef class String
- redef fun serialize_to_json(v) do v.stream.write("\"{to_json_s}\"")
-
- private fun to_json_s: String do return self.replace("\\", "\\\\").
- replace("\"", "\\\"").replace("/", "\\/").
- replace("\n", "\\n").replace("\r", "\\r").replace("\t", "\\t")
- # FIXME add support for unicode char when supported by Nit strings
- # FIXME add support for \f! # .replace("\f", "\\f")
- # FIXME add support for \b .replace("\b", "\\b")
+ redef fun serialize_to_json(v) do v.stream.write(to_json)
end
redef class NativeString
v.notify_of_creation self
var length = v.deserialize_attribute("__length").as(Int)
- var arr = v.path.last["__items"].as(Array[nullable Object])
+ var arr = v.path.last["__items"].as(SequenceRead[nullable Object])
for i in length.times do
var obj = v.convert_object(arr[i])
self.add obj
JavaVM_jni_error(NULL, "Could not attach current thread to Java VM", res);
return NULL;
}
+ return env;
`}
end
# Call a method on `obj` designed by `method_id` with an array `args` of argument returning a JavaObject
fun call_object_method(obj: JavaObject, method_id: JMethodID, args: nullable Array[nullable Object]): JavaObject import convert_args_to_jni `{
jvalue * args_tab = JniEnv_convert_args_to_jni(recv, args);
- (*recv)->CallObjectMethod(recv, obj, method_id, args_tab);
+ jobject res = (*recv)->CallObjectMethod(recv, obj, method_id, args_tab);
free(args_tab);
+ return res;
`}
# Call a method on `obj` designed by `method_id` with an array `args` of arguments returning a Bool
fun call_boolean_method(obj: JavaObject, method_id: JMethodID, args: nullable Array[nullable Object]): Bool import convert_args_to_jni `{
jvalue * args_tab = JniEnv_convert_args_to_jni(recv, args);
- return (*recv)->CallBooleanMethod(recv, obj, method_id, args_tab);
+ jboolean res = (*recv)->CallBooleanMethod(recv, obj, method_id, args_tab);
free(args_tab);
+ return res;
`}
# Call a method on `obj` designed by `method_id` with an array `args` of arguments returning a Char
fun call_char_method(obj: JavaObject, method_id: JMethodID, args: nullable Array[nullable Object]): Char import convert_args_to_jni `{
jvalue * args_tab = JniEnv_convert_args_to_jni(recv, args);
- return (*recv)->CallCharMethod(recv, obj, method_id, args_tab);
+ jchar res = (*recv)->CallCharMethod(recv, obj, method_id, args_tab);
free(args_tab);
+ return res;
`}
# Call a method on `obj` designed by `method_id` with an array `args` of arguments returning an Int
fun call_int_method(obj: JavaObject, method_id: JMethodID, args: nullable Array[nullable Object]): Int import convert_args_to_jni `{
jvalue * args_tab = JniEnv_convert_args_to_jni(recv, args);
- return (*recv)->CallIntMethod(recv, obj, method_id, args_tab);
+ jint res = (*recv)->CallIntMethod(recv, obj, method_id, args_tab);
free(args_tab);
+ return res;
`}
# Call a method on `obj` designed by `method_id` with an array `args` of arguments returning a Float
fun call_float_method(obj: JavaObject, method_id: JMethodID, args: nullable Array[nullable Object]): Float import convert_args_to_jni `{
jvalue * args_tab = JniEnv_convert_args_to_jni(recv, args);
- return (*recv)->CallFloatMethod(recv, obj, method_id, args_tab);
+ jfloat res = (*recv)->CallFloatMethod(recv, obj, method_id, args_tab);
free(args_tab);
+ return res;
`}
# Call a method on `obj` designed by `method_id` with an array `args` of arguments returning a NativeString
# SEE: `String::md_to_html` for a shortcut.
class MarkdownProcessor
+ # `MarkdownEmitter` used for ouput.
var emitter: MarkdownEmitter is noinit
init do self.emitter = new MarkdownEmitter(self)
return new LineOther
end
+ # Get the token kind at `pos`.
+ fun token_at(text: Text, pos: Int): Token do
+ var c0: Char
+ var c1: Char
+ var c2: Char
+
+ if pos > 0 then
+ c0 = text[pos - 1]
+ else
+ c0 = ' '
+ end
+ var c = text[pos]
+
+ if pos + 1 < text.length then
+ c1 = text[pos + 1]
+ else
+ c1 = ' '
+ end
+ if pos + 2 < text.length then
+ c2 = text[pos + 2]
+ else
+ c2 = ' '
+ end
+
+ if c == '*' then
+ if c1 == '*' then
+ if c0 != ' ' or c2 != ' ' then
+ return new TokenStrongStar(pos, c)
+ else
+ return new TokenEmStar(pos, c)
+ end
+ end
+ if c0 != ' ' or c1 != ' ' then
+ return new TokenEmStar(pos, c)
+ else
+ return new TokenNone(pos, c)
+ end
+ else if c == '_' then
+ if c1 == '_' then
+ if c0 != ' ' or c2 != ' 'then
+ return new TokenStrongUnderscore(pos, c)
+ else
+ return new TokenEmUnderscore(pos, c)
+ end
+ end
+ if c0 != ' ' or c1 != ' ' then
+ return new TokenEmUnderscore(pos, c)
+ else
+ return new TokenNone(pos, c)
+ end
+ else if c == '!' then
+ if c1 == '[' then return new TokenImage(pos, c)
+ return new TokenNone(pos, c)
+ else if c == '[' then
+ return new TokenLink(pos, c)
+ else if c == ']' then
+ return new TokenNone(pos, c)
+ else if c == '`' then
+ if c1 == '`' then
+ return new TokenCodeDouble(pos, c)
+ else
+ return new TokenCodeSingle(pos, c)
+ end
+ else if c == '\\' then
+ if c1 == '\\' or c1 == '[' or c1 == ']' or c1 == '(' or c1 == ')' or c1 == '{' or c1 == '}' or c1 == '#' or c1 == '"' or c1 == '\'' or c1 == '.' or c1 == '<' or c1 == '>' or c1 == '*' or c1 == '+' or c1 == '-' or c1 == '_' or c1 == '!' or c1 == '`' or c1 == '~' or c1 == '^' then
+ return new TokenEscape(pos, c)
+ else
+ return new TokenNone(pos, c)
+ end
+ else if c == '<' then
+ return new TokenHTML(pos, c)
+ else if c == '&' then
+ return new TokenEntity(pos, c)
+ else if c == '^' then
+ if c0 == '^' or c1 == '^' then
+ return new TokenNone(pos, c)
+ else
+ return new TokenSuper(pos, c)
+ end
+ else
+ return new TokenNone(pos, c)
+ end
+ end
+
+ # Find the position of a `token` in `self`.
+ fun find_token(text: Text, start: Int, token: Token): Int do
+ var pos = start
+ while pos < text.length do
+ if token_at(text, pos).is_same_type(token) then
+ return pos
+ end
+ pos += 1
+ end
+ return -1
+ end
end
# Emit output corresponding to blocks content.
# Default is `HTMLDecorator`
var decorator: Decorator = new HTMLDecorator is writable
- # Create a new `MardownEmitter` using the default `HTMLDecorator`
- init(processor: MarkdownProcessor) do
- self.processor = processor
- end
-
# Create a new `MarkdownEmitter` using a custom `decorator`.
init with_decorator(processor: MarkdownProcessor, decorator: Decorator) do
init processor
current_text = text
current_pos = start
while current_pos < text.length do
- var mt = text.token_at(current_pos)
+ var mt = processor.token_at(text, current_pos)
if (token != null and not token isa TokenNone) and
(mt.is_same_type(token) or
(token isa TokenEmStar and mt isa TokenStrongStar) or
var next_empty: Bool = false is writable
# Initialize a new MDLine from its string value
- init(value: String) do
- self.value = value
+ init do
self.leading = process_leading
if leading != value.length then
self.is_empty = false
redef fun emit(v) do
var a = pos + next_pos + 1
- var b = v.current_text.find_token(a, self)
+ var b = v.processor.find_token(v.current_text.as(not null), a, self)
if b > 0 then
v.current_pos = b + next_pos
while a < b and v.current_text[a] == ' ' do a += 1
redef class Text
- # Get the token kind at `pos`.
- private fun token_at(pos: Int): Token do
- var c0: Char
- var c1: Char
- var c2: Char
-
- if pos > 0 then
- c0 = self[pos - 1]
- else
- c0 = ' '
- end
- var c = self[pos]
-
- if pos + 1 < length then
- c1 = self[pos + 1]
- else
- c1 = ' '
- end
- if pos + 2 < length then
- c2 = self[pos + 2]
- else
- c2 = ' '
- end
-
- if c == '*' then
- if c1 == '*' then
- if c0 != ' ' or c2 != ' ' then
- return new TokenStrongStar(pos, c)
- else
- return new TokenEmStar(pos, c)
- end
- end
- if c0 != ' ' or c1 != ' ' then
- return new TokenEmStar(pos, c)
- else
- return new TokenNone(pos, c)
- end
- else if c == '_' then
- if c1 == '_' then
- if c0 != ' ' or c2 != ' 'then
- return new TokenStrongUnderscore(pos, c)
- else
- return new TokenEmUnderscore(pos, c)
- end
- end
- if c0 != ' ' or c1 != ' ' then
- return new TokenEmUnderscore(pos, c)
- else
- return new TokenNone(pos, c)
- end
- else if c == '!' then
- if c1 == '[' then return new TokenImage(pos, c)
- return new TokenNone(pos, c)
- else if c == '[' then
- return new TokenLink(pos, c)
- else if c == ']' then
- return new TokenNone(pos, c)
- else if c == '`' then
- if c1 == '`' then
- return new TokenCodeDouble(pos, c)
- else
- return new TokenCodeSingle(pos, c)
- end
- else if c == '\\' then
- if c1 == '\\' or c1 == '[' or c1 == ']' or c1 == '(' or c1 == ')' or c1 == '{' or c1 == '}' or c1 == '#' or c1 == '"' or c1 == '\'' or c1 == '.' or c1 == '<' or c1 == '>' or c1 == '*' or c1 == '+' or c1 == '-' or c1 == '_' or c1 == '!' or c1 == '`' or c1 == '~' or c1 == '^' then
- return new TokenEscape(pos, c)
- else
- return new TokenNone(pos, c)
- end
- else if c == '<' then
- return new TokenHTML(pos, c)
- else if c == '&' then
- return new TokenEntity(pos, c)
- else if c == '^' then
- if c0 == '^' or c1 == '^' then
- return new TokenNone(pos, c)
- else
- return new TokenSuper(pos, c)
- end
- else
- return new TokenNone(pos, c)
- end
- end
-
- # Find the position of a `token` in `self`.
- private fun find_token(start: Int, token: Token): Int do
- var pos = start
- while pos < length do
- if token_at(pos).is_same_type(token) then
- return pos
- end
- pos += 1
- end
- return -1
- end
-
# Get the position of the next non-space character.
private fun skip_spaces(start: Int): Int do
var pos = start
var env = "MNIT_SRAND".environ
if env != "" then
srand_from(env.to_i)
+ else
+ srand_from(0)
end
var input = "MNIT_READ_INPUT".environ
# Additional space to insert horizontally between characters
# A negave value will display tile overlaped
- var hspace: Int = 0 is writable
+ var hspace: Numeric = 0.0 is writable
# Additional space to insert vertically between characters
# A negave value will display tile overlaped
- var vspace: Int = 0 is writable
+ var vspace: Numeric = 0.0 is writable
# The glyph (tile) associated to the caracter `c` according to `chars`
# Returns null if `c` is not in `chars`
# '\n' are rendered as carriage return
fun text(text: String, font: TileSetFont, x, y: Numeric)
do
+ x = x.to_f
var cx = x
- var cy = y
- var sw = font.width + font.hspace
- var sh = font.height + font.vspace
+ var cy = y.to_f
+ var sw = font.width.to_f + font.hspace.to_f
+ var sh = font.height.to_f + font.vspace.to_f
for c in text.chars do
if c == '\n' then
cx = x
# limitations under the License.
# Impements the services of `mnit:app` using the API from the Android ndk
-module android_app
+module android_app is
+ android_manifest_activity """
+ android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
+ android:configChanges="orientation|keyboardHidden"
+ android:screenOrientation="portrait""""
+end
import mnit
import android
int has_alpha;
unsigned int row_bytes;
- png_bytepp row_pointers;
- unsigned char *pixels;
+ png_bytepp row_pointers = NULL;
+ unsigned char *pixels = NULL;
unsigned int i;
unsigned char sig[8];
png_get_IHDR( png_ptr, info_ptr, &width, &height,
&depth, &color_type, NULL, NULL, NULL);
- if (color_type == PNG_COLOR_TYPE_RGBA)
- has_alpha = 1;
- else if (color_type == PNG_COLOR_TYPE_RGB)
- has_alpha = 0;
- else {
- LOGW("unknown color_type");
- goto close_png_ptr;
+ has_alpha = color_type & PNG_COLOR_MASK_ALPHA;
+
+ // If we get gray and alpha only, standardize the format of the pixels.
+ // GA is not supported by OpenGL ES 1.
+ if (!(color_type & PNG_COLOR_MASK_COLOR)) {
+ png_set_gray_to_rgb(png_ptr);
+ png_set_palette_to_rgb(png_ptr);
+ png_read_update_info(png_ptr, info_ptr);
}
LOGW("w: %i, h: %i", width, height);
row_bytes = png_get_rowbytes(png_ptr, info_ptr);
pixels = malloc(row_bytes * height);
- row_pointers = (png_bytep*) malloc(sizeof(png_bytep) * height);
+ row_pointers = (png_bytep*) malloc(sizeof(png_bytep) * height);
- for (i=0; i<height; i++)
- row_pointers[i] = (png_byte*) malloc(row_bytes);
+ for (i=0; i<height; i++)
+ row_pointers[i] = (png_byte*) malloc(row_bytes);
png_read_image(png_ptr, row_pointers);
else
png_destroy_read_struct(&png_ptr, NULL, NULL);
+ if (pixels != NULL)
+ free(pixels);
+
+ if (row_pointers != NULL) {
+ for (i=0; i<height; i++)
+ free(row_pointers[i]);
+ free(row_pointers);
+ }
+
close_stream:
return recv;
`}
# cURL requests compatible with the JSON REST APIs.
module curl_json
-import jsonable
+import json::static
intrude import curl
# An abstract request that defines most of the standard options for Neo4j REST API
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# This file is free software, which comes along with NIT. This software is
+# distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+# without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE. You can modify it is you want, provided this header
+# is kept unaltered, and a notification of the changes is added.
+# You are allowed to redistribute it and sell it, alone or is a part of
+# another product.
+
+# Errors thrown by the `neo4j` library.
+module neo4j::error
+
+import json::static
+
+# An error thrown by the `neo4j` API.
+#
+# var error = new NeoError("ErrorMessage", "ErrorName")
+# assert error.to_json == "\{\"error\":\"ErrorName\",\"message\":\"ErrorMessage\"\}"
+class NeoError
+ super Error
+ super Jsonable
+
+ # The name of the error.
+ #
+ # Used to programmatically distinguish this kind of error from others.
+ var name: String
+
+ redef fun to_json do
+ return "\{\"error\":{name.to_json},\"message\":{message.to_json}\}"
+ end
+
+ redef fun to_s do return "[{name}] {super}"
+end
# end
# assert 2 == graph.nodes.length
init from_json(t: Text) do
- from_json_object(t.to_jsonable.as(JsonObject))
+ from_json_object(t.parse_json.as(JsonObject))
end
# Retrieve the graph from the specified JSON object.
# assert ["foo", "Bar"] == node.labels
# assert 42 == node["baz"]
init from_json(t: Text) do
- from_json_object(t.to_jsonable.as(JsonObject))
+ from_json_object(t.parse_json.as(JsonObject))
end
# Retrieve the node from the specified JSON value.
+++ /dev/null
-# 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.
-
-# Introduce base classes and services for JSON handling.
-module jsonable
-
-import standard
-private import json::json_parser
-private import json::json_lexer
-
-# Something that can be translated to JSON
-interface Jsonable
- # Get the JSON representation of `self`
- fun to_json: String is abstract
-end
-
-redef class String
- super Jsonable
-
- redef fun to_json do
- var res = new FlatBuffer
- res.add '\"'
- for i in [0..self.length[ do
- var char = self[i]
- if char == '\\' then
- res.append("\\\\")
- continue
- else if char == '\"' then
- res.append("\\\"")
- continue
- else if char == '\/' then
- res.append("\\/")
- continue
- else if char == '\n' then
- res.append("\\n")
- continue
- else if char == '\r' then
- res.append("\\r")
- continue
- else if char == '\t' then
- res.append("\\t")
- continue
- end
- res.add char
- end
- res.add '\"'
- return res.write_to_string
- end
-end
-
-redef class Int
- super Jsonable
-
- redef fun to_json do return self.to_s
-end
-
-redef class Float
- super Jsonable
-
- redef fun to_json do return self.to_s
-end
-
-redef class Bool
- super Jsonable
-
- redef fun to_json do return self.to_s
-end
-
-# A JSON Object representation that behaves like a `Map`
-class JsonObject
- super Jsonable
- super Map[String, nullable Jsonable]
-
- private var map = new HashMap[String, nullable Jsonable]
-
- # Create an empty `JsonObject`
- #
- # var obj = new JsonObject
- # assert obj.is_empty
- init do end
-
- # Init the JSON Object from a Nit `Map`
- #
- # var map = new HashMap[String, String]
- # map["foo"] = "bar"
- # map["goo"] = "baz"
- # var obj = new JsonObject.from(map)
- # assert obj.length == 2
- # assert obj["foo"] == "bar"
- # assert obj["goo"] == "baz"
- init from(items: Map[String, nullable Jsonable]) do
- for k, v in items do map[k] = v
- end
-
- redef fun [](key) do return map[key]
- redef fun []=(key, value) do map[key] = value
- redef fun clear do map.clear
- redef fun has_key(key) do return map.has_key(key)
- redef fun is_empty do return map.is_empty
- redef fun iterator do return map.iterator
- redef fun keys do return map.keys
- redef fun values do return map.values
- redef fun length do return map.length
-
- # Advanced query to get a value within `self` or its children.
- #
- # A query is composed of the keys to each object seperated by '.'.
- #
- # REQUIRE `self.has_key(query)`
- #
- # var obj1 = new JsonObject
- # obj1["baz"] = "foobarbaz"
- # var obj2 = new JsonObject
- # obj2["bar"] = obj1
- # var obj3 = new JsonObject
- # obj3["foo"] = obj2
- # assert obj3.get("foo.bar.baz") == "foobarbaz"
- fun get(query: String): nullable Jsonable do
- var keys = query.split(".").reversed
- var key = keys.pop
-
- assert has_key(key)
- var node = self[key]
-
- while not keys.is_empty do
- key = keys.pop
- assert node isa JsonObject and node.has_key(key)
- node = node[key]
- end
- return node
- end
-
- # Create an empty `JsonObject`
- #
- # var obj = new JsonObject
- # obj["foo"] = "bar"
- # assert obj.to_json == "\{\"foo\": \"bar\"\}"
- redef fun to_json do
- var tpl = new Array[String]
- tpl.add "\{"
- var vals = new Array[String]
- for k, v in self do
- if v == null then
- vals.add "{k.to_json}: null"
- else
- vals.add "{k.to_json}: {v.to_json}"
- end
- end
- tpl.add vals.join(",")
- tpl.add "\}"
- return tpl.join("")
- end
-
- redef fun to_s do return to_json
-end
-
-# A JSON Array representation that behaves like a `Sequence`
-class JsonArray
- super Jsonable
- super Sequence[nullable Jsonable]
-
- private var array = new Array[nullable Jsonable]
-
- init do end
-
- # init the JSON Array from a Nit `Collection`
- init from(items: Collection[nullable Jsonable]) do
- array.add_all(items)
- end
-
- redef fun [](key) do return array[key]
- redef fun []=(key, value) do array[key] = value
- redef fun clear do array.clear
- redef fun insert(item, index) do array.insert(item, index)
- redef fun is_empty do return array.is_empty
- redef fun iterator do return array.iterator
- redef fun length do return array.length
- redef fun pop do return array.pop
- redef fun push(value) do array.push(value)
- redef fun remove_at(index) do array.remove_at(index)
- redef fun shift do return array.shift
- redef fun unshift(e) do array.unshift(e)
-
- redef fun to_json do
- var tpl = new Array[String]
- tpl.add "["
- var vals = new Array[String]
- for v in self do
- if v == null then
- vals.add "null"
- else
- vals.add v.to_json
- end
- end
- tpl.add vals.join(",")
- tpl.add "]"
- return tpl.join("")
- end
-
- redef fun to_s do return to_json
-end
-
-# An error in JSON format that can be returned by tools using JSON like parsers.
-#
-# var error = new JsonError("ErrorCode", "ErrorMessage")
-# assert error.to_s == "ErrorCode: ErrorMessage"
-# assert error.to_json == "\{\"error\": \"ErrorCode\", \"message\": \"ErrorMessage\"\}"
-class JsonError
- super Jsonable
-
- # The error code
- var error: String
-
- # The error message
- var message: String
-
- redef fun to_json do
- var tpl = new Array[String]
- tpl.add "\{"
- tpl.add "\"error\": {error.to_json}, "
- tpl.add "\"message\": {message.to_json}"
- tpl.add "\}"
- return tpl.join("")
- end
-
- redef fun to_s do return "{error}: {message}"
-end
-
-# Redef parser
-
-redef class Nvalue
- private fun to_nit_object: nullable Jsonable is abstract
-end
-
-redef class Nvalue_number
- redef fun to_nit_object
- do
- var text = n_number.text
- if text.chars.has('.') or text.chars.has('e') or text.chars.has('E') then return text.to_f
- return text.to_i
- end
-end
-
-redef class Nvalue_string
- redef fun to_nit_object do return n_string.to_nit_string
-end
-
-redef class Nvalue_true
- redef fun to_nit_object do return true
-end
-
-redef class Nvalue_false
- redef fun to_nit_object do return false
-end
-
-redef class Nvalue_null
- redef fun to_nit_object do return null
-end
-
-redef class Nstring
- # FIXME support \n, etc.
- fun to_nit_string: String do
- var res = new FlatBuffer
- var skip = false
- for i in [1..text.length-2] do
- if skip then
- skip = false
- continue
- end
- var char = text[i]
- if char == '\\' and i < text.length - 2 then
- if text[i + 1] == '\\' then
- res.add('\\')
- skip = true
- continue
- end
- if text[i + 1] == '\"' then
- res.add('\"')
- skip = true
- continue
- end
- if text[i + 1] == '/' then
- res.add('\/')
- skip = true
- continue
- end
- if text[i + 1] == 'n' then
- res.add('\n')
- skip = true
- continue
- end
- if text[i + 1] == 'r' then
- res.add('\r')
- skip = true
- continue
- end
- if text[i + 1] == 't' then
- res.add('\t')
- skip = true
- continue
- end
- end
- res.add char
- end
- return res.write_to_string
- end
-end
-
-redef class Nvalue_object
- redef fun to_nit_object
- do
- var obj = new JsonObject
- var members = n_members
- if members != null then
- var pairs = members.pairs
- for pair in pairs do obj[pair.name] = pair.value
- end
- return obj
- end
-end
-
-redef class Nmembers
- fun pairs: Array[Npair] is abstract
-end
-
-redef class Nmembers_tail
- redef fun pairs
- do
- var arr = n_members.pairs
- arr.add n_pair
- return arr
- end
-end
-
-redef class Nmembers_head
- redef fun pairs do return [n_pair]
-end
-
-redef class Npair
- fun name: String do return n_string.to_nit_string
- fun value: nullable Jsonable do return n_value.to_nit_object
-end
-
-redef class Nvalue_array
- redef fun to_nit_object
- do
- var arr = new JsonArray
- var elements = n_elements
- if elements != null then
- var items = elements.items
- for item in items do arr.add(item.to_nit_object)
- end
- return arr
- end
-end
-
-redef class Nelements
- fun items: Array[Nvalue] is abstract
-end
-
-redef class Nelements_tail
- redef fun items
- do
- var items = n_elements.items
- items.add(n_value)
- return items
- end
-end
-
-redef class Nelements_head
- redef fun items do return [n_value]
-end
-
-redef class Text
- # Parse a JSON String as Jsonable entities
- #
- # Example with `JsonObject`"
- #
- # var obj = "\{\"foo\": \{\"bar\": true, \"goo\": [1, 2, 3]\}\}".to_jsonable
- # assert obj isa JsonObject
- # assert obj["foo"] isa JsonObject
- # assert obj["foo"].as(JsonObject)["bar"] == true
- #
- # Example with `JsonArray`
- #
- # var arr = "[1, 2, 3]".to_jsonable
- # assert arr isa JsonArray
- # assert arr.length == 3
- # assert arr.first == 1
- # assert arr.last == 3
- #
- # Example with `String`
- #
- # var str = "\"foo, bar, baz\"".to_jsonable
- # assert str isa String
- # assert str == "foo, bar, baz"
- #
- # Malformed JSON input returns a `JsonError` object
- #
- # var bad = "\{foo: \"bar\"\}".to_jsonable
- # assert bad isa JsonError
- # assert bad.error == "JsonLexerError"
- fun to_jsonable: nullable Jsonable
- do
- var lexer = new Lexer_json(to_s)
- var parser = new Parser_json
- var tokens = lexer.lex
- parser.tokens.add_all(tokens)
- var root_node = parser.parse
- if root_node isa NStart then
- return root_node.n_0.to_nit_object
- else if root_node isa NLexerError then
- var pos = root_node.position
- var msg = "{root_node.message} at {pos or else "<unknown>"} for {root_node}"
- return new JsonError("JsonLexerError", msg)
- else if root_node isa NParserError then
- var pos = root_node.position
- var msg = "{root_node.message} at {pos or else "<unknown>"} for {root_node}"
- return new JsonError("JsonParsingError", msg)
- else abort
- end
-end
-
module neo4j
import curl_json
+import error
# Handles Neo4j server start and stop command
#
# Parse the cURL `response` as a JSON string
private fun parse_response(response: CurlResponse): Jsonable do
if response isa CurlResponseSuccess then
- if response.body_str.is_empty then
+ var str = response.body_str
+ if str.is_empty then return new JsonObject
+ var res = str.parse_json
+ if res isa JsonParseError then
+ var e = new NeoError(res.to_s, "JsonParseError")
+ e.cause = res
+ return e
+ end
+ if res == null then
+ # empty response wrap it in empty object
return new JsonObject
- else
- var str = response.body_str
- var res = str.to_jsonable
- if res == null then
- # empty response wrap it in empty object
- return new JsonObject
- else if res isa JsonObject and res.has_key("exception") then
- var error = "Neo4jError::{res["exception"] or else "null"}"
- var msg = ""
- if res.has_key("message") then
- msg = res["message"].to_s
- end
- return new JsonError(error, msg.to_json)
- else
- return res
+ else if res isa JsonObject and res.has_key("exception") then
+ var error = "Neo4jError::{res["exception"] or else "null"}"
+ var msg = ""
+ if res.has_key("message") then
+ msg = res["message"].to_s
end
+ return new NeoError(msg, error)
+ else
+ return res
end
else if response isa CurlResponseFailed then
- return new JsonError("Curl error", "{response.error_msg} ({response.error_code})")
+ return new NeoError("{response.error_msg} ({response.error_code})", "CurlError")
else
- return new JsonError("Curl error", "Unexpected response '{response}'")
+ return new NeoError("Unexpected response \"{response}\".", "CurlError")
end
end
end
fun save_edges(edges: Collection[NeoEdge]) do for edge in edges do save_edge(edge)
# Execute the batch and update local nodes
- fun execute: List[JsonError] do
+ fun execute: List[NeoError] do
var request = new JsonPOST(client.batch_url, client.curl)
# request.headers["X-Stream"] = "true"
var json_jobs = new JsonArray
end
# Associate data from response in original nodes and edges
- private fun finalize_batch(response: Jsonable): List[JsonError] do
- var errors = new List[JsonError]
+ private fun finalize_batch(response: Jsonable): List[NeoError] do
+ var errors = new List[NeoError]
if not response isa JsonArray then
- errors.add(new JsonError("Neo4jError", "Unexpected batch response format"))
+ errors.add(new NeoError("Unexpected batch response format.", "Neo4jError"))
return errors
end
# print " {res.length} jobs executed"
for res in response do
if not res isa JsonObject then
- errors.add(new JsonError("Neo4jError", "Unexpected job format in batch response"))
+ errors.add(new NeoError("Unexpected job format in batch response.", "Neo4jError"))
continue
end
var id = res["id"].as(Int)
--- /dev/null
+# This file is part of NIT (http://www.nitlanguage.org).
+#
+# Copyright 2014 Alexis Laferrière <alexis.laf@xymus.net>
+#
+# 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.
+
+# Offers some POSIX threads services that are not available on all platforms
+module extra is
+ c_compiler_option("-pthread")
+ c_linker_option("-pthread")
+end
+
+intrude import pthreads
+
+in "C" `{
+ // TODO protect with: #ifdef WITH_LIBGC
+ #ifndef ANDROID
+ #define GC_THREADS
+ #include <gc.h>
+ #endif
+`}
+
+redef extern class NativePthread
+ fun cancel: Bool `{
+ return pthread_cancel(*recv);
+ `}
+end
+
+redef class Thread
+ # Cancel the execution of the thread
+ fun cancel
+ do
+ if native == null then return
+ native.cancel
+ native = null
+ end
+end
+
+# Does not return if the running thread is to be cancelled
+fun test_cancel `{ pthread_testcancel(); `}
+
+private extern class NativePthreadBarrier in "C" `{ pthread_barrier_t * `}
+ new(count: Int) `{
+ pthread_barrier_t *barrier = malloc(sizeof(pthread_barrier_t));
+ int res = pthread_barrier_init(barrier, NULL, count);
+ return barrier;
+ `}
+
+ fun destroy `{ pthread_barrier_destroy(recv); `}
+
+ fun wait `{ pthread_barrier_wait(recv); `}
+end
// TODO protect with: #ifdef WITH_LIBGC
// We might have to add the next line to gc_chooser.c too, especially
// if we get an error like "thread not registered with GC".
+ #ifndef ANDROID
#define GC_THREADS
#include <gc.h>
- //#endif
+ #endif
`}
redef class Sys
return (nullable_Object)thread_return;
`}
- fun cancel: Bool `{
- return pthread_cancel(*recv);
- `}
-
fun attr: NativePthreadAttr `{
pthread_attr_t *pattr = malloc(sizeof(pthread_attr_t));
pthread_getattr_np(*recv, pattr);
# pthread_mutexattr_setrobust_np
end
-private extern class NativePthreadBarrier in "C" `{ pthread_barrier_t * `}
- new(count: Int) `{
- pthread_barrier_t *barrier = malloc(sizeof(pthread_barrier_t));
- int res = pthread_barrier_init(barrier, NULL, count);
- return barrier;
- `}
-
- fun destroy `{ pthread_barrier_destroy(recv); `}
-
- fun wait `{ pthread_barrier_wait(recv); `}
-end
-
private extern class NativePthreadKey in "C" `{ pthread_key_t * `}
new `{
pthread_key_t *key = malloc(sizeof(pthread_key_t));
`}
end
+private extern class NativePthreadCond in "C" `{ pthread_cond_t * `}
+ new `{
+ pthread_cond_t cond;
+ int r = pthread_cond_init(&cond, NULL);
+ if (r == 0) {
+ pthread_cond_t *pcond = malloc(sizeof(pthread_cond_t));
+ memmove(pcond, &cond, sizeof(pthread_cond_t));
+ return pcond;
+ }
+ return NULL;
+ `}
+
+ fun destroy `{ pthread_cond_destroy(recv); `}
+
+ fun signal `{ pthread_cond_signal(recv); `}
+
+ fun broadcast `{ pthread_cond_broadcast(recv); `}
+
+ fun wait(mutex: NativePthreadMutex) `{ pthread_cond_wait(recv, mutex); `}
+end
+
#
## Nity part
#
return r
end
- # Cancel the execution of the thread
- fun cancel
- do
- if native == null then return
- native.cancel
- native = null
- end
-
redef fun finalize
do
if native == null then return
# Exit current thread and return `value` to caller of `Thread::join`
fun exit_thread(value: nullable Object) `{ pthread_exit(value); `}
-# Does not return if the running thread is to be cancelled
-fun test_cancel `{ pthread_testcancel(); `}
-
# Returns the handle to the running `Thread`
fun thread: Thread
do
class Barrier
super Finalizable
+ private var mutex = new Mutex
+ private var cond: nullable NativePthreadCond = new NativePthreadCond
+
# Number of threads that must be waiting for `wait` to unblock
var count: Int
- private var native: nullable NativePthreadBarrier is noinit
-
- init do native = new NativePthreadBarrier(count)
+ private var threads_waiting = 0
# Wait at this barrier and block until there are a `count` threads waiting
- fun wait do native.wait
+ fun wait
+ do
+ mutex.lock
+ threads_waiting += 1
+ if threads_waiting == count then
+ threads_waiting = 0
+ cond.broadcast
+ else
+ cond.wait(mutex.native.as(not null))
+ end
+ mutex.unlock
+ end
redef fun finalize
do
- var native = self.native
- if native != null then
- native.destroy
- native.free
+ var cond = self.cond
+ if cond != null then
+ cond.destroy
+ cond.free
end
- self.native = null
+ self.cond = null
end
end
# assert a == b
class Array[E]
super AbstractArray[E]
- super ArrayCapable[E]
redef fun [](index)
do
var c = _capacity
if cap <= c then return
while c <= cap do c = c * 2 + 2
- var a = calloc_array(c)
+ var a = new NativeArray[E](c)
if _capacity > 0 then _items.copy_to(a, _length)
_items = a
_capacity = c
init with_capacity(cap: Int)
do
assert positive: cap >= 0
- _items = calloc_array(cap)
+ _items = new NativeArray[E](cap)
_capacity = cap
_length = 0
end
init filled_with(value: E, count: Int)
do
assert positive: count >= 0
- _items = calloc_array(count)
+ _items = new NativeArray[E](count)
_capacity = count
_length = count
var i = 0
# Native classes ##############################################################
-# Subclasses of this class can create native arrays
-interface ArrayCapable[E]
- # Get a new array of `size` elements.
- protected fun calloc_array(size: Int): NativeArray[E] is intern
-end
-
# Native Nit array
# Access are unchecked and it has a fixed size
# Not for public use: may become private.
import array
# A HashCollection is an array of HashNode[K] indexed by the K hash value
-private abstract class HashCollection[K: Object, N: HashNode[Object]]
- super ArrayCapable[nullable N]
+private abstract class HashCollection[K: Object]
+ type N: HashNode[K]
private var array: nullable NativeArray[nullable N] = null # Used to store items
private var capacity: Int = 0 # Size of _array
_last_accessed_key = null
# get a new array
- var new_array = calloc_array(cap)
+ var new_array = new NativeArray[nullable N](cap)
_array = new_array
# clean the new array
# Keys of such a map cannot be null and require a working `hash` method
class HashMap[K: Object, V]
super Map[K, V]
- super HashCollection[K, HashMapNode[K, V]]
+ super HashCollection[K]
+
+ redef type N: HashMapNode[K, V] is fixed
redef fun [](key)
do
# Keys of such a map cannot be null and require a working `hash` method
class HashSet[E: Object]
super Set[E]
- super HashCollection[E, HashSetNode[E]]
+ super HashCollection[E]
+
+ redef type N: HashSetNode[E] is fixed
redef fun length do return _the_length
# The node in the hiearchical structure for each element
private var nodes = new HashMap[E, DisjointSetNode]
+ # The number of subsets in the partition
+ #
+ # var s = new DisjointSet[Int]
+ # s.add_all([1,2,3,4,5])
+ # assert s.number_of_subsets == 5
+ # s.union_all([1,4,5])
+ # assert s.number_of_subsets == 3
+ # s.union(4,5)
+ # assert s.number_of_subsets == 3
+ var number_of_subsets: Int = 0
+
# Get the root node of an element
# require: `has(e)`
private fun find(e:E): DisjointSetNode
if nodes.has_key(e) then return
var ne = new DisjointSetNode
nodes[e] = ne
+ number_of_subsets += 1
end
# Are two elements in the same subset?
ne.rank = er+1
end
end
+ number_of_subsets -= 1
end
# Combine the subsets of all elements of `es`
end
end
+ # Compare float numbers with a given precision.
+ #
+ # Because of the loss of precision in floating numbers,
+ # the `==` method is often not the best way to compare them.
+ #
+ # ~~~
+ # assert 0.01.is_approx(0.02, 0.1) == true
+ # assert 0.01.is_approx(0.02, 0.001) == false
+ # ~~~
+ fun is_approx(other, precision: Float): Bool
+ do
+ assert precision >= 0.0
+ return self <= other + precision and self >= other - precision
+ end
+
redef fun max(other)
do
if self < other then
# assert 2.0.floor == 2.0
# assert (-1.5).floor == -2.0
fun floor: Float `{ return floor(recv); `}
+
+ # Rounds the value of a float to its nearest integer value
+ #
+ # assert 1.67.round == 2.0
+ # assert 1.34.round == 1.0
+ # assert -1.34.round == -1.0
+ # assert -1.67.round == -2.0
+ fun round: Float is extern "round"
# Returns a random `Float` in `[0.0 .. self[`.
fun rand: Float is extern "kernel_Float_Float_rand_0"
end
end
+redef class Sys
+ init
+ do
+ srand
+ end
+end
+
fun atan2(x: Float, y: Float): Float is extern "kernel_Any_Any_atan2_2"
fun pi: Float is extern "kernel_Any_Any_pi_0"
+
+# Initialize the pseudo-random generator with the given seed.
+# The pseudo-random generator is used by the method `rand` and other to generate sequence of numbers.
+# These sequences are repeatable by calling `srand_from` with a same seed value.
+#
+# ~~~~
+# srand_from(0)
+# var a = 10.rand
+# var b = 100.rand
+# srand_from(0)
+# assert 10.rand == a
+# assert 100.rand == b
+# ~~~~
fun srand_from(x: Int) is extern "kernel_Any_Any_srand_from_1"
+
+# Reinitialize the pseudo-random generator used by the method `rand` and other.
+# This method is automatically invoked at the begin of the program, so usually, there is no need to manually invoke it.
+# The only exception is in conjunction with `srand_from` to reset the pseudo-random generator.
fun srand is extern "kernel_Any_Any_srand_0"
# High-level abstraction for all text representations
abstract class Text
super Comparable
- super StringCapable
redef type OTHER: Text
return b.to_s
end
+ # Escape to include in a Makefile
+ #
+ # Unfortunately, some characters are not escapable in Makefile.
+ # These characters are `;`, `|`, `\`, and the non-printable ones.
+ # They will be rendered as `"?{hex}"`.
+ fun escape_to_mk: String do
+ var b = new FlatBuffer
+ for i in [0..length[ do
+ var c = chars[i]
+ if c == '$' then
+ b.append("$$")
+ else if c == ':' or c == ' ' or c == '#' then
+ b.add('\\')
+ b.add(c)
+ else if c.ascii < 32 or c == ';' or c == '|' or c == '\\' or c == '=' then
+ b.append("?{c.ascii.to_base(16, false)}")
+ else
+ b.add(c)
+ end
+ end
+ return b.to_s
+ end
+
# Return a string where Nit escape sequences are transformed.
#
# var s = "\\n"
redef fun reversed
do
- var native = calloc_string(self.length + 1)
+ var native = new NativeString(self.length + 1)
var length = self.length
var items = self.items
var pos = 0
redef fun to_upper
do
- var outstr = calloc_string(self.length + 1)
+ var outstr = new NativeString(self.length + 1)
var out_index = 0
var myitems = self.items
redef fun to_lower
do
- var outstr = calloc_string(self.length + 1)
+ var outstr = new NativeString(self.length + 1)
var out_index = 0
var myitems = self.items
if real_items != null then
return real_items.as(not null)
else
- var newItems = calloc_string(length + 1)
+ var newItems = new NativeString(length + 1)
self.items.copy_to(newItems, length, index_from, 0)
newItems[length] = '\0'
self.real_items = newItems
var total_length = my_length + its_length
- var target_string = calloc_string(my_length + its_length + 1)
+ var target_string = new NativeString(my_length + its_length + 1)
self.items.copy_to(target_string, my_length, index_from, 0)
if s isa FlatString then
var my_items = self.items
- var target_string = calloc_string((final_length) + 1)
+ var target_string = new NativeString(final_length + 1)
target_string[final_length] = '\0'
# The COW flag can be set at false here, since
# it does a copy of the current `Buffer`
written = false
- var a = calloc_string(c+1)
+ var a = new NativeString(c+1)
if length > 0 then items.copy_to(a, length, 0, 0)
items = a
capacity = c
redef fun to_cstring
do
if is_dirty then
- var new_native = calloc_string(length + 1)
+ var new_native = new NativeString(length + 1)
new_native[length] = '\0'
if length > 0 then items.copy_to(new_native, length, 0, 0)
real_items = new_native
do
capacity = s.length + 1
length = s.length
- items = calloc_string(capacity)
+ items = new NativeString(capacity)
if s isa FlatString then
s.items.copy_to(items, length, s.index_from, 0)
else if s isa FlatBuffer then
do
assert cap >= 0
# _items = new NativeString.calloc(cap)
- items = calloc_string(cap+1)
+ items = new NativeString(cap+1)
capacity = cap
length = 0
end
redef fun reverse
do
written = false
- var ns = calloc_string(capacity)
+ var ns = new NativeString(capacity)
var si = length - 1
var ni = 0
var it = items
private class FlatBufferCharView
super BufferCharView
- super StringCapable
redef type SELFTYPE: FlatBuffer
# Native strings are simple C char *
extern class NativeString `{ char* `}
- super StringCapable
# Creates a new NativeString with a capacity of `length`
new(length: Int) is intern
fun [](index: Int): Char is intern
fun to_s_with_copy: FlatString
do
var length = cstring_length
- var new_self = calloc_string(length + 1)
+ 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)
new_self[length] = '\0'
end
end
-# StringCapable objects can create native strings
-interface StringCapable
- protected fun calloc_string(size: Int): NativeString is intern
-end
-
redef class Sys
private var args_cache: nullable Sequence[String]
// Integer to NativeString method
char* native_int_to_s(long recv){
int len = snprintf(NULL, 0, "%ld", recv);
- char* str = malloc(len);
+ char* str = malloc(len+1);
sprintf(str, "%ld", recv);
return str;
}
redef fun to_cstring
do
if real_items != null then return real_items.as(not null)
- var new_items = calloc_string(bytelen + 1)
+ var new_items = new NativeString(bytelen + 1)
self.items.copy_to(new_items, bytelen, index[index_from].pos, 0)
new_items[bytelen] = '\0'
self.real_items = new_items
redef fun reversed
do
- var native = calloc_string(self.bytelen + 1)
+ var native = new NativeString(self.bytelen + 1)
var length = self.length
var index = self.index
var pos = 0
var my_real_len = length
var my_real_fin_len = my_real_len * i
- var target_string = calloc_string((finlen) + 1)
+ var target_string = new NativeString((finlen) + 1)
var my_index = index
var new_index = new StringIndex(my_real_fin_len)
redef fun to_upper
do
- var outstr = calloc_string(self.bytelen + 1)
+ var outstr = new NativeString(self.bytelen + 1)
var out_index = 0
var index = self.index
redef fun to_lower
do
- var outstr = calloc_string(self.bytelen + 1)
+ var outstr = new NativeString(self.bytelen + 1)
var out_index = 0
var index = self.index
var real_len = new Container[Int](0)
var length = cstring_length
var x = make_index(length, real_len)
- var new_self = calloc_string(length + 1)
+ var new_self = new NativeString(length + 1)
copy_to(new_self, length, 0, 0)
return new FlatString.with_infos_index(new_self, real_len.item, 0, real_len.item - 1, x, length)
end
end
redef fun reversed do
- var new_str = calloc_string(bytelen)
+ var new_str = new NativeString(bytelen)
var s_pos = bytelen
var my_pos = index_from
var its = items
end
redef fun to_upper do
- var ns = calloc_string(bytelen)
+ var ns = new NativeString(bytelen)
var offset = 0
for i in [0 .. length[
do
end
redef fun to_lower do
- var ns = calloc_string(bytelen)
+ var ns = new NativeString(bytelen)
var offset = 0
for i in [0 .. length[
do
redef fun +(o) do
if o isa Buffer then o = o.to_s
if o isa FlatString then
- var new_str = calloc_string(bytelen + o.bytelen + 1)
+ var new_str = new NativeString(bytelen + o.bytelen + 1)
var new_bytelen = bytelen + o.bytelen
new_str[new_bytelen] = '\0'
var newlen = length + o.length
var new_bytelen = mybtlen * i
var mylen = length
var newlen = mylen * i
- var ns = calloc_string(new_bytelen + 1)
+ var ns = new NativeString(new_bytelen + 1)
ns[new_bytelen] = '\0'
var offset = 0
while i > 0 do
redef fun to_cstring do
if real_items != null then return real_items.as(not null)
- var new_items = calloc_string(bytelen + 1)
+ var new_items = new NativeString(bytelen + 1)
self.items.copy_to(new_items, bytelen, index_from, 0)
new_items[bytelen] = '\0'
self.real_items = new_items
with_capacity(50)
for i in s.substrings do self.append(i)
end
- items = calloc_string(s.bytelen)
+ items = new NativeString(s.bytelen)
if s isa FlatString then
s.items.copy_to(items, s.bytelen, s.index_from, 0)
else
var c = capacity
if cap <= c then return
while c <= cap do c = c * 2 + 2
- var a = calloc_string(c+1)
+ var a = new NativeString(c+1)
if bytelen > 0 then items.copy_to(a, bytelen, 0, 0)
items = a
capacity = c
redef fun reverse
do
- var nns = calloc_string(bytelen)
+ var nns = new NativeString(bytelen)
var ns = items
var btlen = bytelen
var myp = 0
end
redef fun to_cstring do
- var ns = calloc_string(bytelen)
+ var ns = new NativeString(bytelen)
items.copy_to(ns, bytelen, 0, 0)
return ns
end
redef fun to_s_with_copy
do
var length = cstring_length
- var new_self = calloc_string(length + 1)
+ var new_self = new NativeString(length + 1)
copy_to(new_self, length, 0, 0)
return new FlatString.with_bytelen(new_self, 0, length - 1, length)
end
var outname = outfile(mainmodule)
- var outpath = compile_dir.relpath(outname)
+ var real_outpath = compile_dir.relpath(outname)
+ var outpath = real_outpath.escape_to_mk
+ if outpath != real_outpath then
+ # If the name is crazy and need escaping, we will do an indirection
+ # 1. generate the binary in the .nit_compile dir under an escaped name
+ # 2. copy the binary at the right place in the `all` goal.
+ outpath = mainmodule.c_name
+ end
var makename = makefile_name(mainmodule)
var makepath = "{compile_dir}/{makename}"
var makefile = new OFStream.open(makepath)
makefile.write("ifdef NEED_LIBUNWIND\n\tLDLIBS += -lunwind\nendif\n")
- makefile.write("all: {outpath}\n\n")
+ makefile.write("all: {outpath}\n")
+ if outpath != real_outpath then
+ makefile.write("\tcp -- {outpath.escape_to_sh} {real_outpath.escape_to_sh.replace("$","$$")}")
+ end
+ makefile.write("\n")
var ofiles = new Array[String]
var dep_rules = new Array[String]
if not pkgconfigs.is_empty then
pkg = "`pkg-config --libs {pkgconfigs.join(" ")}`"
end
- makefile.write("{outpath}: {dep_rules.join(" ")}\n\t$(CC) $(LDFLAGS) -o {outpath} {ofiles.join(" ")} $(LDLIBS) {pkg}\n\n")
+ makefile.write("{outpath}: {dep_rules.join(" ")}\n\t$(CC) $(LDFLAGS) -o {outpath.escape_to_sh} {ofiles.join(" ")} $(LDLIBS) {pkg}\n\n")
# Clean
- makefile.write("clean:\n\trm {ofiles.join(" ")} 2>/dev/null\n\n")
+ makefile.write("clean:\n\trm {ofiles.join(" ")} 2>/dev/null\n")
+ if outpath != real_outpath then
+ makefile.write("\trm -- {outpath.escape_to_sh} 2>/dev/null\n")
+ end
makefile.close
self.toolcontext.info("Generated makefile: {makepath}", 2)
stream.write("static const C_Nit_Names map[{names.length}] = \{\n")
for i in names.keys do
stream.write("\{\"")
- stream.write(i)
+ stream.write(i.escape_to_c)
stream.write("\",\"")
- stream.write(names[i])
+ stream.write(names[i].escape_to_c)
stream.write("\"\},\n")
end
stream.write("\};\n")
# Custom lines to add to the AndroidManifest.xml in the <application> node
var manifest_application_lines = new Array[String]
+ # Custom lines to add to AndroidManifest.xml as attributes inside the <activity> node
+ var manifest_activity_attributes = new Array[String]
+
# Minimum API level required for the application to run
var min_api: nullable Int = null
annots = collect_annotations_on_modules("android_manifest_application", mmodule)
for an in annots do project.manifest_application_lines.add an.arg_as_string(self) or else ""
+ annots = collect_annotations_on_modules("android_manifest_activity", mmodule)
+ for an in annots do project.manifest_activity_attributes.add an.arg_as_string(self) or else ""
+
# Get the date and time (down to the minute) as string
var local_time = new Tm.localtime
var local_time_s = local_time.strftime("%y%m%d%H%M")
# Also copy over the java files
dir = "{android_project_root}/src/"
- var extra_java_files = compiler.mainmodule.extra_java_files
- if extra_java_files != null then for file in extra_java_files do
- var path = file.filename
- path.file_copy_to("{dir}/{path.basename("")}")
+ for mmodule in compiler.mainmodule.in_importation.greaters do
+ var extra_java_files = mmodule.extra_java_files
+ if extra_java_files != null then for file in extra_java_files do
+ var path = file.filename
+ path.file_copy_to(dir/path.basename(""))
+ end
end
## Generate delagating makefile
This will take care of integrating with our NDK code. -->
<activity android:name="android.app.NativeActivity"
android:label="@string/app_name"
- android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
- android:configChanges="orientation|keyboardHidden"
- android:screenOrientation="portrait"
+ {{{project.manifest_activity_attributes.join("\n")}}}
{{{icon_declaration}}}>
- <!-- Tell NativeActivity the name of or .so -->
- <meta-data android:name=\"{{{app_package}}}\"
- android:value=\"{{{app_name}}}\" />
+ <!-- Tell NativeActivity the name of our .so -->
+ <meta-data android:name=\"android.app.lib_name\"
+ android:value=\"main\" />
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
init
do
- var file = new_file("{mainmodule.name}.nitgg")
+ var file = new_file("{mainmodule.c_name}.nitgg")
self.header = new CodeWriter(file)
self.live_primitive_types = new Array[MClassType]
for t in runtime_type_analysis.live_types do
redef fun native_array_instance(elttype: MType, length: RuntimeVariable): RuntimeVariable
do
var ret_type = self.get_class("NativeArray").get_mtype([elttype])
+ ret_type = anchor(ret_type).as(MClassType)
return self.new_expr("NEW_{ret_type.c_name}({length})", ret_type)
end
import toolcontext
import doc_model
+private import json::static
redef class ToolContext
private var opt_dir = new OptionString("output directory", "-d", "--dir")
# All entities are grouped by name to make the research easier.
class QuickSearch
- private var mmodules = new HashSet[MModule]
- private var mclasses = new HashSet[MClass]
- private var mpropdefs = new HashMap[String, Set[MPropDef]]
+ private var table = new QuickSearchTable
var ctx: ToolContext
var model: Model
init do
for mmodule in model.mmodules do
if mmodule.is_fictive then continue
- mmodules.add mmodule
+ add_result_for(mmodule.name, mmodule.full_name, mmodule.nitdoc_url)
end
for mclass in model.mclasses do
if mclass.visibility < ctx.min_visibility then continue
- mclasses.add mclass
+ add_result_for(mclass.name, mclass.full_name, mclass.nitdoc_url)
end
for mproperty in model.mproperties do
if mproperty.visibility < ctx.min_visibility then continue
if mproperty isa MAttribute then continue
- if not mpropdefs.has_key(mproperty.name) then
- mpropdefs[mproperty.name] = new HashSet[MPropDef]
+ for mpropdef in mproperty.mpropdefs do
+ var full_name = mpropdef.mclassdef.mclass.full_name
+ var cls_url = mpropdef.mclassdef.mclass.nitdoc_url
+ var def_url = "{cls_url}#{mpropdef.mproperty.nitdoc_id}"
+ add_result_for(mproperty.name, full_name, def_url)
end
- mpropdefs[mproperty.name].add_all(mproperty.mpropdefs)
end
end
+ private fun add_result_for(query: String, txt: String, url: String) do
+ table[query].add new QuickSearchResult(txt, url)
+ end
+
fun render: Template do
var tpl = new Template
- tpl.add "var nitdocQuickSearchRawList=\{ "
- for mmodule in mmodules do
- tpl.add "\"{mmodule.name}\":["
- tpl.add "\{txt:\"{mmodule.full_name}\",url:\"{mmodule.nitdoc_url}\"\},"
- tpl.add "],"
- end
- for mclass in mclasses do
- var full_name = mclass.intro.mmodule.full_name
- tpl.add "\"{mclass.name}\":["
- tpl.add "\{txt:\"{full_name}\",url:\"{mclass.nitdoc_url}\"\},"
- tpl.add "],"
- end
- for mproperty, mprops in mpropdefs do
- tpl.add "\"{mproperty}\":["
- for mpropdef in mprops do
- var full_name = mpropdef.mclassdef.mclass.full_name
- var cls_url = mpropdef.mclassdef.mclass.nitdoc_url
- var def_url = "{cls_url}#{mpropdef.mproperty.nitdoc_id}"
- tpl.add "\{txt:\"{full_name}\",url:\"{def_url}\"\},"
- end
- tpl.add "],"
- end
- tpl.add " \};"
+ var buffer = new RopeBuffer
+ tpl.add buffer
+ buffer.append "var nitdocQuickSearchRawList="
+ table.append_json buffer
+ buffer.append ";"
return tpl
end
end
+# The result map for QuickSearch.
+private class QuickSearchTable
+ super JsonMapRead[String, QuickSearchResultList]
+ super HashMap[String, QuickSearchResultList]
+
+ redef fun provide_default_value(key) do
+ var v = new QuickSearchResultList
+ self[key] = v
+ return v
+ end
+end
+
+# A QuickSearch result list.
+private class QuickSearchResultList
+ super JsonSequenceRead[QuickSearchResult]
+ super Array[QuickSearchResult]
+end
+
+# A QuickSearch result.
+private class QuickSearchResult
+ super Jsonable
+
+ # The text of the link.
+ var txt: String
+
+ # The destination of the link.
+ var url: String
+
+ redef fun to_json do
+ return "\{\"txt\":{txt.to_json},\"url\":{url.to_json}\}"
+ end
+end
+
# Nitdoc base page
# Define page structure and properties
abstract class NitdocPage
# Tell the C compiler where to find jni.h and how to link with libjvm
private fun insert_compiler_options
do
- c_compiler_options = "{c_compiler_options} -I $(JAVA_HOME)/include/"
+ c_compiler_options = "{c_compiler_options} -I $(JAVA_HOME)/include/ -I $(JAVA_HOME)/include/linux/"
c_linker_options = "{c_linker_options} -L $(JNI_LIB_PATH) -ljvm"
end
return v.bool_instance(args[0].to_f.is_nan)
else if pname == "is_inf_extern" then
return v.bool_instance(args[0].to_f.is_inf != 0)
+ else if pname == "round" then
+ return v.float_instance(args[0].to_f.round)
end
else if cname == "NativeString" then
if pname == "new" then
return v.native_string_instance(txt)
else if pname == "get_time" then
return v.int_instance(get_time)
+ else if pname == "srand" then
+ srand
+ return null
else if pname == "srand_from" then
srand_from(args[1].to_i)
return null
# The lines of the current code block, empty is no current code block
var curblock = new Array[String]
+ # Count empty lines between code blocks
+ var empty_lines = 0
+
fun work(mdoc: MDoc): HTMLTag
do
var root = new HTMLTag("div")
# Is codeblock? Then just collect them
if indent >= 3 then
+ for i in [0..empty_lines[ do curblock.add("")
+ empty_lines = 0
# to allows 4 spaces including the one that follows the #
curblock.add(text)
continue
end
- # Was a codblock just before the current line ?
- close_codeblock(n or else root)
-
# fence opening
if text.substring(0,3) == "~~~" then
+ # Was a codblock just before the current line ?
+ close_codeblock(n or else root)
+
var l = 3
while l < text.length and text.chars[l] == '~' do l += 1
in_fence = text.substring(0, l)
if text.is_empty or indent < lastindent then
n = null
ul = null
- if text.is_empty then continue
+ if text.is_empty then
+ if not curblock.is_empty then empty_lines += 1
+ continue
+ end
end
+ # Was a codblock just before the current line ?
+ close_codeblock(n or else root)
+
# Special first word: new paragraph
if text.has_prefix("TODO") or text.has_prefix("FIXME") then
n = new HTMLTag("p")
do
# Is there a codeblock to manage?
if not curblock.is_empty then
+ empty_lines = 0
+
# determine the smalest indent
var minindent = -1
for text in curblock do
var indent = 0
while indent < text.length and text.chars[indent] == ' ' do indent += 1
+ # skip white lines
+ if indent >= text.length then continue
if minindent == -1 or indent < minindent then
minindent = indent
end
end
+ if minindent < 0 then minindent = 0
# Generate the text
var btext = new FlatBuffer
self.toolcontext.info("{mmodule} imports {imported_modules.join(", ")}", 3)
mmodule.set_imported_mmodules(imported_modules)
+ # Force standard to be public if imported
+ for sup in mmodule.in_importation.greaters do
+ if sup.name == "standard" then
+ mmodule.set_visibility_for(sup, public_visibility)
+ end
+ end
+
# TODO: Correctly check for useless importation
# It is even doable?
var directs = mmodule.in_importation.direct_greaters
redef fun process_code(n: HTMLTag, text: String)
do
+ # Skip non-blocks
+ if n.tag != "pre" then return
+
# Try to parse it
var ast = toolcontext.parse_something(text)
toolcontext.modelbuilder.unit_entities += 1
cpt += 1
- var file = "{prefix}{cpt}.nit"
+ var file = "{prefix}-{cpt}.nit"
toolcontext.info("Execute doc-unit {tc.attrs["name"]} in {file}", 1)
--- /dev/null
+# 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.
+
+import kernel
+
+1.output
--- /dev/null
+# 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.
+
+private import template
+
+print 1
--- /dev/null
+# 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.
+
+import base_import_standard
+
+print 2
'B'.output
'1'.output
' '.output
- inita
+ super
'B'.output
'2'.output
' '.output
'C'.output
'1'.output
' '.output
- inita
+ super
'C'.output
'2'.output
' '.output
super C
init do
'D'.output
- '0'.output
- ' '.output
-#alt1# inita
-#alt3# inita
-#alt5# inita
-#alt7# inita
-#alt9# inita
-#alt11# inita
-#alt13# inita
-#alt15# inita
- 'D'.output
'1'.output
' '.output
-#alt2# initb
-#alt3# initb
-#alt6# initb
-#alt7# initb
-#alt10# initb
-#alt11# initb
-#alt14# initb
-#alt15# initb
+ super
'D'.output
'2'.output
' '.output
-#alt4# initc
-#alt5# initc
-#alt6# initc
-#alt7# initc
-#alt12# initc
-#alt13# initc
-#alt14# initc
-#alt15# initc
- 'D'.output
- '3'.output
- ' '.output
-#alt8# inite
-#alt9# inite
-#alt10# inite
-#alt11# inite
-#alt12# inite
-#alt13# inite
-#alt14# inite
-#alt15# inite
- 'D'.output
- '4'.output
- ' '.output
end
init inite do
'C'.output
'1'.output
' '.output
- inita
+ super
'C'.output
'2'.output
' '.output
bcm2835
-gtk3_6
-gtk3_8
-posix_ext
-physical_interface_for_mpd_on_rpi
blink
input
-android_app
-android_assets
-opengles1
-init_inherit
-init_linext
# See the License for the specific language governing permissions and
# limitations under the License.
-import end
-class Object
-end
+import kernel
class A
- fun toto do end
+ fun toto do 1.output
end
class B
super A
- redef fun toto do end
+ redef fun toto do 2.output
end
class C
super A
- redef fun toto do end
+ redef fun toto do 3.output
end
class D
super B
super C
end
+
+(new A).toto
+(new B).toto
+(new C).toto
+#alt1#(new D).toto
-init_inherit
-init_linext
-init_inherit
-init_linext
nitg
+nitdoc
-init_inherit
-init_linext
-init_inherit
-init_linext
-android
-init_inherit
-init_linext
test_mem
shoot_logic
bench_
nitg_args8
test_markdown_args1
pep8analysis
-nitcc_parser_gen
emscripten
nitserial_args
nitunit_args
test_nitunit.nit --no-color -o $WRITE
test_nitunit.nit --gen-suite --only-show
test_nitunit.nit --gen-suite --only-show --private
+test_nitunit2.nit -o $WRITE
-init_inherit
-init_linext
test_mem
shoot_logic
bench_
-Runtime error: Assert 'index' failed (../lib/standard/collection/array.nit:258)
+Expected two numbers
C{B{A}}cba
Ama
A2ma
-B{A}nbma
-O{C{B{A}}}onmcba
+B{A}nmba
+O{C{B{A}}}oncmba
Aba
Aca
Amca
-Anbmca
+Anmcba
B{A}ba
Aca
Amca
-B{A}nbmca
+B{A}nmcba
Aba
C{A}ca
C{A}mca
-C{A}nbmca
+C{A}nmcba
-alt/base_init_inherit2_alt3.nit:75,7: Error: Explicit constructor required in N since multiple inheritance of constructor is forbiden. Conflicting classes are B, C. Costructors are base_init_inherit2_alt3::B::cb, base_init_inherit2_alt3::A::ca, base_init_inherit2_alt3::C::cc.
+Aa
Ama
B{A}ba
Ana
-B{A}omba
-B{A}pbna
-B{A}qmbna
+B{A}obma
+B{A}pnba
+B{A}qnbma
Ama
B{A}ba
Ana
-B{A}omba
-B{A}pbna
-B{A}qombna
+B{A}obma
+B{A}pnba
+B{A}qonbma
Ama
B{A}ba
Ana
-B{A}omba
-B{A}pbna
-B{A}qmpbna
+B{A}obma
+B{A}pnba
+B{A}qpnbma
Ama
B{A}ba
Ana
-B{A}omba
-B{A}pbna
-B{A}qompbna
+B{A}obma
+B{A}pnba
+B{A}qponbma
Bba
-Bomba
-Bpbna
-Bqmbna
+Bobma
+Bpnba
+Bqnbma
Bba
-Bomba
-Bpbna
-Bqombna
+Bobma
+Bpnba
+Bqonbma
Bba
-Bomba
-Bpbna
-Bqmpbna
+Bobma
+Bpnba
+Bqpnbma
Bba
-Bomba
-Bpbna
-Bqompbna
+Bobma
+Bpnba
+Bqponbma
B2{A1}ba
C3{B2{A1}}cba
A1ma
-B2{A1}nbma
-O4{C3{B2{A1}}}onmcba
+B2{A1}nmba
+O4{C3{B2{A1}}}oncmba
-alt/base_init_inherit6_alt1.nit:32,10--14: Error: init is not a constructor in B.
+1
+2
+1
+3
+1
-alt/base_init_inherit6_alt2.nit:33,10--18: Error: foo is not a constructor in B.
+1
+2
+1
+3
+2
-alt/base_init_inherit_alt1.nit:95,2--9: Error: ca is not a constructor in B.
-alt/base_init_inherit_alt1.nit:96,2--10: Error: ca2 is not a constructor in B.
-alt/base_init_inherit_alt1.nit:98,2--9: Error: ca is not a constructor in C.
-alt/base_init_inherit_alt1.nit:99,2--10: Error: ca2 is not a constructor in C.
-alt/base_init_inherit_alt1.nit:100,2--9: Error: cb is not a constructor in C.
-alt/base_init_inherit_alt1.nit:104,2--9: Error: ca is not a constructor in N.
-alt/base_init_inherit_alt1.nit:105,2--10: Error: ca2 is not a constructor in N.
-alt/base_init_inherit_alt1.nit:107,2--9: Error: ca is not a constructor in O.
-alt/base_init_inherit_alt1.nit:108,2--10: Error: ca2 is not a constructor in O.
-alt/base_init_inherit_alt1.nit:109,2--9: Error: cb is not a constructor in O.
-alt/base_init_inherit_alt1.nit:110,2--9: Error: cc is not a constructor in O.
+Aa
+A2a
+B{A}ba
+Aba
+A2ba
+C{B{A}}cba
+Acba
+A2cba
+B{A}cba
+Ama
+A2ma
+B{A}nmba
+Anmba
+A2nmba
+O{C{B{A}}}oncmba
+Aoncmba
+A2oncmba
+B{A}oncmba
+C{B{A}}oncmba
-B1 A B2 C1 C2 D0 D1 D2 D3 D4
+D1 C1 B1 A B2 C2 D2
B1 A B2
A B3
A B4y
-C1 A C2
+C1 C2
A2z C3z
-D1 B1 A B2 C1 C2 D2 D3
+D1 B1 A B2 D2 D3
-alt/base_init_linext2_alt1.nit:100,1--5: Error: No contructor named initd in superclasses.
+alt/base_init_linext2_alt1.nit:100,1--5: Error: No super method to call for initd.
-alt/base_init_linext2_alt2.nit:99,2--5: Error: there is no available compatible constructor in B. Discarded candidates are base_init_linext2_alt2::B::initb, base_init_linext2_alt2::B::init_par, base_init_linext2_alt2::B::init_par2(c: Char).
+A
+A2x
+B1 A B2
+A B3
+A B4y
+C1 C2
+A2z C3z
+C1 C2 D1 D2 D3
B1 A B2
A B3
A B4y
-C1 A C2
+C1 C2
A2z C3z
D1 B1 A B2 D2 C1 C2 D3
-alt/base_init_linext2_alt4.nit:99,2--5: Error: there is no available compatible constructor in B. Discarded candidates are base_init_linext2_alt4::B::initb, base_init_linext2_alt4::B::init_par, base_init_linext2_alt4::B::init_par2(c: Char).
+A
+A2x
+B1 A B2
+A B3
+A B4y
+C1 C2
+A2z C3z
+D1 C1 C2 B1 A B2 D2 D3
-alt/base_init_linext2_alt5.nit:109,1--5: Error: Only one super constructor invocation of class B is allowed.
+A
+A2x
+B1 A B2
+A B3
+A B4y
+C1 C2
+A2z C3z
+D1 B1 A B2 D2 B1 A B2 D3
A
B1 A B2
C1 A C2
-B1 A B2 C1 C2 D0 D1 D2 D3 D4
-E1 A E2 B1 B2 E3 C1 C2 E4
+D1 C1 B1 A B2 C2 D2
+E1 D1 C1 B1 A B2 C2 D2 E2 D1 C1 B1 A B2 C2 D2 E3 D1 C1 B1 A B2 C2 D2 E4
+++ /dev/null
-D0 A B1 B2 C1 C2 D1 D2 D3 D4
+++ /dev/null
-D0 D1 B1 A B2 D2 D3 E1 E2 E3 C1 C2 E4 D4
+++ /dev/null
-D0 A D1 B1 B2 D2 D3 E1 E2 E3 C1 C2 E4 D4
+++ /dev/null
-D0 D1 D2 C1 A C2 D3 E1 E2 B1 B2 E3 E4 D4
+++ /dev/null
-D0 A D1 D2 C1 C2 D3 E1 E2 B1 B2 E3 E4 D4
+++ /dev/null
-D0 D1 B1 A B2 D2 C1 C2 D3 E1 E2 E3 E4 D4
+++ /dev/null
-D0 A D1 B1 B2 D2 C1 C2 D3 E1 E2 E3 E4 D4
+++ /dev/null
-D0 D1 B1 A B2 C1 C2 D2 D3 D4
+++ /dev/null
-D0 A D1 B1 B2 C1 C2 D2 D3 D4
+++ /dev/null
-B1 A B2 D0 D1 D2 C1 C2 D3 D4
+++ /dev/null
-D0 A B1 B2 D1 D2 C1 C2 D3 D4
+++ /dev/null
-D0 D1 B1 A B2 D2 C1 C2 D3 D4
+++ /dev/null
-D0 A D1 B1 B2 D2 C1 C2 D3 D4
+++ /dev/null
-D0 D1 D2 D3 E1 A E2 B1 B2 E3 C1 C2 E4 D4
+++ /dev/null
-D0 A D1 D2 D3 E1 E2 B1 B2 E3 C1 C2 E4 D4
A
b1 B1 A B2 b2
c1 C1 A C2 c2
-d1 b1 B1 A B2 b2 c1 C1 C2 c2 D0 D1 D2 D3 D4 d2
+d1 D1 c1 C1 b1 B1 A B2 b2 C2 c2 D2 d2
-Property inheritance conflict in class D for `toto': conflicting properties are defined in B, C
+1
+2
+3
--- /dev/null
+alt/error_prop_loc_alt1.nit:38,1--12: Warning: conflicting property definitions for property toto in D: error_prop_loc_alt1#B#toto error_prop_loc_alt1#C#toto
+1
+2
+3
+3
-alt/error_redef_1alt4_alt5.nit:30,12--13: Redef error: The procedure B::f1 redefines the function A::f1.
-alt/error_redef_1alt4_alt9.nit:34,15: Syntax error: untyped parameter.
+++ /dev/null
-1
-1
-5
-5
-1
-2
-5
-2
-1
-1
-3
-7
-1
-2
-3
-4
+++ /dev/null
-base_for_nullable.nit:21,10--13: Type error: 'for' on a nullable expression.
+++ /dev/null
-alt/base_for_nullable_alt1.nit:21,10--13: Type error: 'for' on a nullable expression.
+++ /dev/null
-alt/base_for_nullable_alt2.nit:21,10--13: Type error: 'for' on a nullable expression.
-Runtime error: Cast failed. Expected `OTHER`, got `Float` (../lib/standard/kernel.nit:396)
+Runtime error: Cast failed. Expected `OTHER`, got `Float` (../lib/standard/kernel.nit:411)
11
21
31
-Runtime error: Cast failed. Expected `OTHER`, got `Float` (../lib/standard/kernel.nit:396)
+Runtime error: Cast failed. Expected `OTHER`, got `Float` (../lib/standard/kernel.nit:411)
11
21
31
-Runtime error: Cast failed. Expected `OTHER`, got `Float` (../lib/standard/kernel.nit:396)
+Runtime error: Cast failed. Expected `OTHER`, got `Float` (../lib/standard/kernel.nit:411)
11
21
31
+++ /dev/null
-0
-0
-1
-2
-10
-20
-30
+++ /dev/null
-1
-0
-1
-2
-10
-20
-30
+++ /dev/null
-0
-0
-0
-1
-2
-10
-20
-30
+++ /dev/null
-10
-0
-1
-2
-10
-20
-30
+++ /dev/null
-10
-20
-0
-1
-2
-10
-20
-30
+++ /dev/null
-1
-1
-1
-aa
+++ /dev/null
-1
-1
-1
-1
-a
+++ /dev/null
-true
-true
-true
-false
-true
+++ /dev/null
-1
-2
-3
-0
-
-1
-100
-2
-0
-
-1
-10
-20
-100
-2
-10
+++ /dev/null
-0
-0
-1
-2
-10
-20
-30
+++ /dev/null
-1
-0
-1
-2
-10
-20
-30
+++ /dev/null
-0
-0
-0
-1
-2
-10
-20
-30
+++ /dev/null
-10
-0
-1
-2
-10
-20
-30
+++ /dev/null
-10
-20
-0
-1
-2
-10
-20
-30
+++ /dev/null
-1
-1
-1
-aa
+++ /dev/null
-1
-1
-1
-1
-a
+++ /dev/null
-true
-true
-true
-false
-true
+++ /dev/null
-1
-2
-3
-0
-
-1
-100
-2
-0
-
-1
-10
-20
-100
-2
-10
+++ /dev/null
-0
-0
-1
-2
-10
-20
-30
+++ /dev/null
-1
-0
-1
-2
-10
-20
-30
+++ /dev/null
-0
-0
-0
-1
-2
-10
-20
-30
+++ /dev/null
-10
-0
-1
-2
-10
-20
-30
+++ /dev/null
-10
-20
-0
-1
-2
-10
-20
-30
+++ /dev/null
-1
-1
-1
-aa
+++ /dev/null
-1
-1
-1
-1
-a
+++ /dev/null
-true
-true
-true
-false
-true
+++ /dev/null
-1
-2
-3
-0
-
-1
-100
-2
-0
-
-1
-10
-20
-100
-2
-10
if name == "Array[Serializable]" then return new Array[Serializable].from_deserializer(self)
if name == "Array[String]" then return new Array[String].from_deserializer(self)
if name == "Array[Object]" then return new Array[Object].from_deserializer(self)
- if name == "Array[Match]" then return new Array[Match].from_deserializer(self)
- if name == "Array[FlatBuffer]" then return new Array[FlatBuffer].from_deserializer(self)
return super
end
end
Object -> Bool [dir=back arrowtail=open style=dashed];
Float [
- label = "{Float||}"
+ label = "{Float||+ is_approx(other: Float, precision: Float): Bool\l}"
]
Numeric -> Float [dir=back arrowtail=open style=dashed];
Object -> Bool [dir=back arrowtail=open style=dashed];
Float [
- label = "{Float||}"
+ label = "{Float||+ is_approx(other: Float, precision: Float): Bool\l}"
]
Numeric -> Float [dir=back arrowtail=open style=dashed];
-test_nitunit.nit:20,1--22,0: ERROR: nitunit.test_nitunit.test_nitunit::X.<class> (in .nitunit/test_nitunit2.nit): Runtime error: Assert failed (.nitunit/test_nitunit2.nit:5)
+test_nitunit.nit:20,1--22,0: ERROR: nitunit.test_nitunit.test_nitunit::X.<class> (in .nitunit/test_nitunit-2.nit): Runtime error: Assert failed (.nitunit/test_nitunit-2.nit:5)
-test_nitunit.nit:23,2--25,0: FAILURE: nitunit.test_nitunit.test_nitunit::X.test_nitunit::X::foo (in .nitunit/test_nitunit3.nit): .nitunit/test_nitunit3.nit:5,8--27: Error: Method or variable 'undefined_identifier' unknown in Sys.
+test_nitunit.nit:23,2--25,0: FAILURE: nitunit.test_nitunit.test_nitunit::X.test_nitunit::X::foo (in .nitunit/test_nitunit-3.nit): .nitunit/test_nitunit-3.nit:5,8--27: Error: Method or variable 'undefined_identifier' unknown in Sys.
test_test_nitunit.nit:36,2--40,4: ERROR: test_foo1 (in file .nitunit/test_test_nitunit_TestX_test_foo1.nit): Runtime error: Assert failed (test_test_nitunit.nit:39)
Class suites: 1; Test Cases: 3; Failures: 1
<testsuites><testsuite package="test_nitunit"><testcase classname="nitunit.test_nitunit.<module>" name="<module>"><system-err></system-err><system-out>assert true
</system-out></testcase><testcase classname="nitunit.test_nitunit.test_nitunit::X" name="<class>"><system-err></system-err><system-out>assert false
-</system-out><error message="Runtime error: Assert failed (.nitunit/test_nitunit2.nit:5)
+</system-out><error message="Runtime error: Assert failed (.nitunit/test_nitunit-2.nit:5)
"></error></testcase><testcase classname="nitunit.test_nitunit.test_nitunit::X" name="test_nitunit::X::foo"><system-err></system-err><system-out>assert undefined_identifier
-</system-out><failure message=".nitunit/test_nitunit3.nit:5,8--27: Error: Method or variable 'undefined_identifier' unknown in Sys.
+</system-out><failure message=".nitunit/test_nitunit-3.nit:5,8--27: Error: Method or variable 'undefined_identifier' unknown in Sys.
"></failure></testcase></testsuite><testsuite package="test_test_nitunit"><testcase classname="nitunit.test_test_nitunit.test_test_nitunit::TestX" name="test_test_nitunit::TestX::test_foo"><system-err></system-err><system-out>out</system-out></testcase><testcase classname="nitunit.test_test_nitunit.test_test_nitunit::TestX" name="test_test_nitunit::TestX::test_foo1"><system-err></system-err><system-out>out</system-out><error message="Runtime error: Assert failed (test_test_nitunit.nit:39)
"></error></testcase><testcase classname="nitunit.test_test_nitunit.test_test_nitunit::TestX" name="test_test_nitunit::TestX::test_foo2"><system-err></system-err><system-out>out</system-out></testcase></testsuite></testsuites>
\ No newline at end of file
--- /dev/null
+DocUnits:
+DocUnits Success
+Entities: 4; Documented ones: 3; With nitunits: 3; Failures: 0
+
+TestSuites:
+No test cases found
+Class suites: 0; Test Cases: 0; Failures: 0
+<testsuites><testsuite package="test_nitunit2"><testcase classname="nitunit.test_nitunit2.standard::kernel::Object" name="test_nitunit2::Object::foo1"><system-err></system-err><system-out>if true then
+
+ assert true
+
+end
+</system-out></testcase><testcase classname="nitunit.test_nitunit2.standard::kernel::Object" name="test_nitunit2::Object::bar2"><system-err></system-err><system-out>if true then
+
+ assert true
+
+end
+</system-out></testcase><testcase classname="nitunit.test_nitunit2.standard::kernel::Object" name="test_nitunit2::Object::foo3"><system-err></system-err><system-out>var a = 1
+assert a == 1
+assert a == 1
+</system-out></testcase></testsuite><testsuite></testsuite></testsuites>
\ No newline at end of file
-Property inheritance conflict in class B for `i': conflicting properties are defined in B, A
+1
+1
+5
+5
+1
+2
+5
+2
+1
+1
+3
+7
+1
+2
+3
+4
-Runtime error: Cast failed. Expected `E`, got `Bool` (../lib/standard/collection/array.nit:789)
+Runtime error: Cast failed. Expected `E`, got `Bool` (../lib/standard/collection/array.nit:782)
NativeString
N
Nit
stop=false
while [ "$stop" = false ]; do
- case $1 in
+ case "$1" in
-v) verbose=true; shift;;
*) stop=true
esac
echo "$f"
continue
fi
- b=`basename "$f" .nit`
+ b=`basename -- "$f" .nit`
;;
*.res)
- b=`basename "$f" .res`
+ b=`basename -- "$f" .res`
;;
*)
- b=`basename "$f"`
+ b=`basename -- "$f"`
;;
esac
+ # remove bad chars
+ c=`echo "$b" | sed 's/\([\\.*^$]\|\[\|]\)/./g'`
# Remove alts of args test variations
- c=`echo "$b" | sed 's/\(_[0-9]*alt[0-9][0-9]*\)/\\\\(\1\\\\)\\\\?/g;s/\(_args[0-9][0-9]*\)/\\\\(\1\\\\)\\\\?/'`
+ c=`echo "$c" | sed 's/\(_[0-9]*alt[0-9][0-9]*\)/\\\\(\1\\\\)\\\\?/g;s/\(_args[0-9][0-9]*\)/\\\\(\1\\\\)\\\\?/'`
b=`echo "$b" | sed 's/_[0-9]*alt[0-9][0-9]*//g;s/_args[0-9][0-9]*//'`
# Search the orig nit file in the list
- cat listfull.out | grep "\b$c.nit" || {
+ cat listfull.out | grep -- "\(^\|/\)$c.nit" || {
res=1
echo >&2 "No test $b.nit found for $f"
test "$verbose" == "true" || continue
# Search the nit file outside the list...
- find ../../nit* -name $b.nit >&2
+ find ../../nit* -name "$b.nit" >&2
# Search the nit file in the git history...
- git log -1 -- $b.nit >&2
+ git log -1 -- "$b.nit" >&2
# Search the orig file in the git history...
- git log -1 -- $f >&2
+ git log -1 -- "$f" >&2
}
done
return new ArrayList();
`}
- fun add(o: Int) in "Java" `{ recv.add(o); `}
+ fun add(o: JavaString) in "Java" `{ recv.add(o); `}
redef fun output in "Java" `{
for (Object i: recv) {
- System.out.println((long)i);
+ System.out.println((String)i);
}
`}
end
var ll = new JavaArrayList
-ll.add(1)
-ll.add(2)
-ll.add(1)
-ll.add(3)
-ll.add(20)
-ll.add(10)
+ll.add "1".to_java_string
+ll.add "2".to_java_string
+ll.add "1".to_java_string
+ll.add "3".to_java_string
+ll.add "20".to_java_string
+ll.add "10".to_java_string
ll.output
ll.sort
ll.output
end
class TestNative
- super ArrayCapable[Int]
+
init
do
a[1] = 2
print(a[0])
print(a[1])
- b = calloc_array(5)
+ b = new NativeArray[Int](5)
b[0]=200
b[1]=300
print(b[0])
# This file is part of NIT ( http://www.nitlanguage.org ).
#
# Copyright 2014 Alexis Laferrière <alexis.laf@xymus.net>
+# Copyright 2014 Jean-Christophe Beaupré <jcbrinfo@users.noreply.github.com>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
var a = "\{\"__kind\": \"obj\", \"__id\": 0, \"__class\": \"C\", \"a\": \{\"__kind\": \"obj\", \"__id\": 1, \"__class\": \"A\", \"b\": true, \"c\": \"a\", \"f\": 0.123, \"i\": 1234, \"s\": \"asdf\", \"n\": null, \"array\": [88, \"hello\", null]\}, \"b\": \{\"__kind\": \"obj\", \"__id\": 2, \"__class\": \"B\", \"b\": false, \"c\": \"b\", \"f\": 123.123, \"i\": 2345, \"s\": \"hjkl\", \"n\": null, \"array\": [88, \"hello\", null], \"ii\": 1111, \"ss\": \"qwer\"\}, \"aa\": \{\"__kind\": \"ref\", \"__id\": 1\}\}"
var b = "\{\"__kind\": \"obj\", \"__id\": 0, \"__class\": \"A\", \"b\": true, \"c\": \"a\", \"f\": 0.123, \"i\": 1234, \"s\": \"asdf\", \"n\": null, \"array\": [88, \"hello\", null]\}"
+var c = "\{\"foo\":\"bar\\\"\\\\\\/\\b\\f\\n\\r\\t\\u0020\\u0000\"\}"
+var d = "\{ \"face with tears of joy\" : \"\\uD83D\\uDE02\" \}"
-for s in [a, b] do
- var obj = s.json_to_nit_object
+for s in [a, b, c, d] do
+ var obj = s.parse_json
print "# Json: {s}"
print "# Nit: {obj or else "<null>"}"
end
# limitations under the License.
class Toto
- super ArrayCapable[Int]
+
fun toto
do
- var a = calloc_array(3)
+ var a = new NativeArray[Int](3)
a[0] = 10
a[1] = 20
a[2] = 30
print res1["name"].to_s
print res1["age"].to_s
print res1["status"].to_s
-print res1["groups"].to_s
+print res1["groups"].to_json
print res1.labels.join(" ")
assert res1.out_edges.is_empty
print res4["name"].to_s
print res4["age"].to_s
print res4["status"].to_s
-print res4["groups"].to_s
+print res4["groups"].to_json
print res4.labels.join(" ")
assert res4.in_edges.is_empty
assert not res4.out_edges.is_empty
print res4["name"].to_s
print res4["age"].to_s
print res4["status"].to_s
-print res4["groups"].to_s
+print res4["groups"].to_json
print res4.labels.join(" ")
assert res4.in_edges.is_empty
assert not res4.out_edges.is_empty
--- /dev/null
+# 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.
+
+# a fence unit
+#
+# ~~~~
+# if true then
+#
+# assert true
+#
+# end
+# ~~~~
+fun foo1 do end
+
+# a block unit
+#
+# if true then
+#
+# assert true
+#
+# end
+fun bar2 do end
+
+# a context continuation
+#
+# var a = 1
+# assert a == 1
+#
+# bla bla
+#
+# assert a == 1
+fun foo3 do end
# Get the first Java lib available
shopt -s nullglob
-paths=`echo /usr/lib/jvm/*/`
-paths=($paths)
-JAVA_HOME=${paths[0]}
+JAVA_HOME=$(dirname $(dirname $(readlink -f $(which javac))))
paths=`echo $JAVA_HOME/jre/lib/*/{client,server}/`
paths=($paths)
JNI_LIB_PATH=${paths[0]}
+echo $JAVA_HOME
+echo $JNI_LIB_PATH
shopt -u nullglob
outdir="out"
local o=
local a=
while [ $stop = false ]; do
- case $1 in
+ case "$1" in
-o) o="$2"; shift; shift;;
-a) a="-a"; shift;;
*) stop=true
local pattern="$1"
local sav="$2"
if [ ! -r "$sav" ]; then return 0; fi
- test "`cat "$sav"`" = "UNDEFINED" && return 1
- diff -u "$sav" "$outdir/$pattern.res" > "$outdir/$pattern.diff.sav.log"
+ test "`cat -- "$sav"`" = "UNDEFINED" && return 1
+ diff -u -- "$sav" "$outdir/$pattern.res" > "$outdir/$pattern.diff.sav.log"
if [ "$?" == 0 ]; then
return 1
fi
fi
}
+function xmlesc()
+{
+ sed 's/&/\&/g; s/</\</g; s/>/\>/g; s/"/\"/g; s/'"'"'/\'/g'<<EOF
+$*
+EOF
+}
+
# As argument: the pattern used for the file
function process_result()
{
OLD=""
LIST=""
FIRST=""
- echo >>$xml "<testcase classname='$pack' name='$description' time='`cat $outdir/$pattern.time.out`' `timestamp`>"
+ echo >>$xml "<testcase classname='`xmlesc "$pack"`' name='`xmlesc "$description"`' time='`cat -- "$outdir/$pattern.time.out"`' `timestamp`>"
#for sav in "sav/$engine/fixme/$pattern.res" "sav/$engine/$pattern.res" "sav/fixme/$pattern.res" "sav/$pattern.res" "sav/$pattern.sav"; do
for savdir in $savdirs; do
sav=$savdir/fixme/$pattern.res
if [ -n "$SAV" ]; then
if [ -n "$OLD" ]; then
echo "[*ok*] $outdir/$pattern.res $SAV - but $OLD remains!"
- echo >>$xml "<error message='ok $outdir/$pattern.res - but $OLD remains'/>"
+ echo >>$xml "<error message='`xmlesc "ok $outdir/$pattern.res - but $OLD remains"`'/>"
remains="$remains $OLD"
else
echo "[ok] $outdir/$pattern.res $SAV"
elif [ -n "$FIXME" ]; then
if [ -n "$OLD" ]; then
echo "[*fixme*] $outdir/$pattern.res $FIXME - but $OLD remains!"
- echo >>$xml "<error message='ok $outdir/$pattern.res - but $OLD remains'/>"
+ echo >>$xml "<error message='`xmlesc "ok $outdir/$pattern.res - but $OLD remains"`'/>"
remains="$remains $OLD"
else
echo "[fixme] $outdir/$pattern.res $FIXME"
todos="$todos $pattern"
elif [ -n "$SOSO" ]; then
echo "[======= soso $outdir/$pattern.res $SOSO =======]"
- echo >>$xml "<error message='soso $outdir/$pattern.res $SOSO'/>"
+ echo >>$xml "<error message='`xmlesc "soso $outdir/$pattern.res $SOSO"`'/>"
echo >>$xml "<system-out><![CDATA["
- cat -v $outdir/$pattern.diff.sav.log | head >>$xml -n 50
+ cat -v -- "$outdir/$pattern.diff.sav.log" | head >>$xml -n 50
echo >>$xml "]]></system-out>"
nok="$nok $pattern"
echo "$ii" >> "$ERRLIST"
elif [ -n "$SOSOF" ]; then
echo "[======= fixme soso $outdir/$pattern.res $SOSOF =======]"
- echo >>$xml "<error message='soso $outdir/$pattern.res $SOSO'/>"
+ echo >>$xml "<error message='`xmlesc "soso $outdir/$pattern.res $SOSO"`'/>"
echo >>$xml "<system-out><![CDATA["
- cat -v $outdir/$pattern.diff.sav.log | head >>$xml -n 50
+ cat -v -- "$outdir/$pattern.diff.sav.log" | head >>$xml -n 50
echo >>$xml "]]></system-out>"
nok="$nok $pattern"
echo "$ii" >> "$ERRLIST"
elif [ -n "$NSAV" ]; then
echo "[======= fail $outdir/$pattern.res $NSAV =======]"
- echo >>$xml "<error message='fail $outdir/$pattern.res $NSAV'/>"
+ echo >>$xml "<error message='`xmlesc "fail $outdir/$pattern.res $NSAV"`'/>"
echo >>$xml "<system-out><![CDATA["
- cat -v $outdir/$pattern.diff.sav.log | head >>$xml -n 50
+ cat -v -- "$outdir/$pattern.diff.sav.log" | head >>$xml -n 50
echo >>$xml "]]></system-out>"
nok="$nok $pattern"
echo "$ii" >> "$ERRLIST"
elif [ -n "$NFIXME" ]; then
echo "[======= changed $outdir/$pattern.res $NFIXME ======]"
- echo >>$xml "<error message='changed $outdir/$pattern.res $NFIXME'/>"
+ echo >>$xml "<error message='`xmlesc "changed $outdir/$pattern.res $NFIXME"`'/>"
echo >>$xml "<system-out><![CDATA["
- cat -v $outdir/$pattern.diff.sav.log | head >>$xml -n 50
+ cat -v -- "$outdir/$pattern.diff.sav.log" | head >>$xml -n 50
echo >>$xml "]]></system-out>"
nok="$nok $pattern"
echo "$ii" >> "$ERRLIST"
- elif [ -s $outdir/$pattern.res ]; then
+ elif [ -s "$outdir/$pattern.res" ]; then
echo "[=== no sav ===] $outdir/$pattern.res is not empty"
echo >>$xml "<error message='no sav and not empty'/>"
echo >>$xml "<system-out><![CDATA["
- cat -v >>$xml $outdir/$pattern.res
+ cat -v >>$xml -- "$outdir/$pattern.res"
echo >>$xml "]]></system-out>"
nos="$nos $pattern"
echo "$ii" >> "$ERRLIST"
echo "[0k] $outdir/$pattern.res is empty"
ok="$ok $pattern"
fi
- if test -s $outdir/$pattern.cmp.err; then
+ if test -s "$outdir/$pattern.cmp.err"; then
echo >>$xml "<system-err><![CDATA["
- cat -v >>$xml $outdir/$pattern.cmp.err
+ cat -v >>$xml -- "$outdir/$pattern.cmp.err"
echo >>$xml "]]></system-err>"
fi
echo >>$xml "</testcase>"
test "$noskip" = true && return 1
if echo "$1" | grep -f "$engine.skip" >/dev/null 2>&1; then
echo "=> $2: [skip]"
- echo >>$xml "<testcase classname='$3' name='$2' `timestamp`><skipped/></testcase>"
+ echo >>$xml "<testcase classname='`xmlesc "$3"`' name='`xmlesc "$2"`' `timestamp`><skipped/></testcase>"
return 0
fi
if test -n "$isinterpret" && echo "$1" | grep -f "exec.skip" >/dev/null 2>&1; then
echo "=> $2: [skip exec]"
- echo >>$xml "<testcase classname='$3' name='$2' `timestamp`><skipped/></testcase>"
+ echo >>$xml "<testcase classname='`xmlesc "$3"`' name='`xmlesc "$2"`' `timestamp`><skipped/></testcase>"
return 0
fi
return 1
engine=nitg-s;
enginebinname=nitg;
OPT="--separate $OPT --compile-dir $compdir"
+ savdirs="sav/nitg-common/"
;;
nitg-s)
enginebinname=nitg;
OPT="--separate $OPT --compile-dir $compdir"
+ savdirs="sav/nitg-common/"
;;
nitg-e)
enginebinname=nitg;
OPT="--erasure $OPT --compile-dir $compdir"
+ savdirs="sav/nitg-common/"
;;
nitg-sg)
enginebinname=nitg;
OPT="--semi-global $OPT --compile-dir $compdir"
+ savdirs="sav/nitg-common/"
;;
nitg-g)
enginebinname=nitg;
OPT="--global $OPT --compile-dir $compdir"
+ savdirs="sav/nitg-common/"
;;
nit)
engine=niti
echo >$xml "<testsuites><testsuite>"
for ii in "$@"; do
- if [ ! -f $ii ]; then
+ if [ ! -f "$ii" ]; then
echo "File '$ii' does not exist."
continue
fi
- f=`basename "$ii" .nit`
+ f=`basename -- "$ii" .nit`
pack="tests.${engine}".`echo $ii | perl -p -e 's|^../([^/]*)/([a-zA-Z_]*).*|\1.\2| || s|^([a-zA-Z]*)[^_]*_([a-zA-Z]*).*|\1.\2| || s|\W*([a-zA-Z_]*).*|\1|'`
# Sould we skip the file for this engine?
- need_skip $f $f $pack && continue
+ need_skip "$f" "$f" "$pack" && continue
tmp=${ii/../AA}
if [ "x$tmp" = "x$ii" ]; then
includes="-I alt"
fi
- for i in "$ii" `./alterner.pl --start '#' --altsep '_' $ii`; do
- bf=`basename $i .nit`
+ for i in "$ii" `./alterner.pl --start '#' --altsep '_' -- "$ii"`; do
+ bf=`basename -- "$i" .nit`
ff="$outdir/$bf"
# Sould we skip the alternative for this engine?
- need_skip $bf $bf $pack && continue
+ need_skip "$bf" "$bf" "$pack" && continue
echo -n "=> $bf: "
if [ -n "$isinterpret" ]; then
cat > "$ff.bin" <<END
-exec $NITC --no-color $OPT $includes -- "$i" "\$@"
+exec $NITC --no-color $OPT $includes -- $(printf '%q' "$i") "\$@"
END
chmod +x "$ff.bin"
> "$ff.cmp.err"
saferun -o "$ff.time.out" $NITC --no-color $OPT -o "$ffout" $includes $nocc "$i" 2> "$ff.cmp.err" > "$ff.compile.log"
ERR=$?
if [ "x$verbose" = "xtrue" ]; then
- cat "$ff.compile.log"
- cat >&2 "$ff.cmp.err"
+ cat -- "$ff.compile.log"
+ cat >&2 -- "$ff.cmp.err"
fi
fi
if [ "$engine" = "emscripten" ]; then
chmod +x "$ff.bin"
if grep "Fatal Error: more than one primitive class" "$ff.compile.log" > /dev/null; then
echo " [skip] do no not imports kernel"
- echo >>$xml "<testcase classname='$pack' name='$bf' `timestamp`><skipped/></testcase>"
+ echo >>$xml "<testcase classname='`xmlesc "$pack"`' name='`xmlesc "$bf"`' `timestamp`><skipped/></testcase>"
continue
fi
fi
if [ "$ERR" != 0 ]; then
echo -n "! "
- cat "$ff.compile.log" "$ff.cmp.err" > "$ff.res"
- process_result $bf $bf $pack
+ cat -- "$ff.compile.log" "$ff.cmp.err" > "$ff.res"
+ process_result "$bf" "$bf" "$pack"
elif [ -n "$nocc" ]; then
# not compiled
echo -n "nocc "
> "$ff.res"
- process_result $bf $bf $pack
+ process_result "$bf" "$bf" "$pack"
elif [ -x "$ff.bin" ]; then
if skip_exec "$bf"; then
# No exec
> "$ff.res"
- process_result $bf $bf $pack
+ process_result "$bf" "$bf" "$pack"
break
fi
echo -n ". "
fi
NIT_NO_STACK=1 LD_LIBRARY_PATH=$JNI_LIB_PATH \
saferun -a -o "$ff.time.out" "$ff.bin" $args < "$inputs" > "$ff.res" 2>"$ff.err"
- mv $ff.time.out $ff.times.out
- awk '{ SUM += $1} END { print SUM }' $ff.times.out > $ff.time.out
+ mv "$ff.time.out" "$ff.times.out"
+ awk '{ SUM += $1} END { print SUM }' "$ff.times.out" > "$ff.time.out"
if [ "x$verbose" = "xtrue" ]; then
- cat "$ff.res"
- cat >&2 "$ff.err"
+ cat -- "$ff.res"
+ cat >&2 -- "$ff.err"
fi
if [ -f "$ff.write" ]; then
- cat "$ff.write" >> "$ff.res"
+ cat -- "$ff.write" >> "$ff.res"
elif [ -d "$ff.write" ]; then
- LANG=C /bin/ls -F $ff.write >> "$ff.res"
+ LANG=C /bin/ls -F "$ff.write" >> "$ff.res"
fi
- cp "$ff.res" "$ff.res2"
- cat "$ff.cmp.err" "$ff.err" "$ff.res2" > "$ff.res"
- process_result $bf $bf $pack
+ cp -- "$ff.res" "$ff.res2"
+ cat -- "$ff.cmp.err" "$ff.err" "$ff.res2" > "$ff.res"
+ process_result "$bf" "$bf" "$pack"
if [ -f "$f.args" ]; then
fargs=$f.args
name="$bf args $cptr"
# Sould we skip the input for this engine?
- need_skip $bff " $name" $pack && continue
+ need_skip "$bff" " $name" "$pack" && continue
# use a specific inputs file, if required
if [ -f "$bff.inputs" ]; then
ffinputs="$bff.inputs"
else
- ffinputs=$inputs
+ ffinputs="$inputs"
fi
rm -rf "$fff.res" "$fff.err" "$fff.write" 2> /dev/null
chmod +x "$fff.bin"
WRITE="$fff.write" saferun -o "$fff.time.out" sh -c "NIT_NO_STACK=1 $fff.bin < $ffinputs > $fff.res 2>$fff.err"
if [ "x$verbose" = "xtrue" ]; then
- cat "$fff.res"
- cat >&2 "$fff.err"
+ cat -- "$fff.res"
+ cat >&2 -- "$fff.err"
fi
if [ -f "$fff.write" ]; then
- cat "$fff.write" >> "$fff.res"
+ cat -- "$fff.write" >> "$fff.res"
elif [ -d "$fff.write" ]; then
- LANG=C /bin/ls -F $fff.write >> "$fff.res"
+ LANG=C /bin/ls -F -- "$fff.write" >> "$fff.res"
fi
if [ -s "$fff.err" ]; then
- cp "$fff.res" "$fff.res2"
- cat "$fff.err" "$fff.res2" > "$fff.res"
+ cp -- "$fff.res" "$fff.res2"
+ cat -- "$fff.err" "$fff.res2" > "$fff.res"
fi
- process_result $bff " $name" $pack
- done < $fargs
+ process_result "$bff" " $name" "$pack"
+ done < "$fargs"
fi
elif [ -f "$ff.bin" ]; then
#Not executable (platform?)"
> "$ff.res"
- process_result $bf "$bf" $pack
+ process_result "$bf" "$bf" "$pack"
else
echo -n "! "
- cat "$ff.cmp.err" > "$ff.res"
+ cat -- "$ff.cmp.err" > "$ff.res"
echo "Compilation error" > "$ff.res"
- process_result $bf "$bf" $pack
+ process_result "$bf" "$bf" "$pack"
fi
done
done