From: Jean Privat Date: Sat, 30 May 2015 00:37:01 +0000 (-0400) Subject: Merge: Byte data type X-Git-Tag: v0.7.5~7 X-Git-Url: http://nitlanguage.org?hp=db4059439cb2d72e5e8ccc97449037503cd014b1 Merge: Byte data type As discussed in #1267, we need a Byte data type to manipulate low-level data as numerics instead of how it is done for now using chars. This PR will serve as base for future updates, notably related to #1370 which will introduce a way to express Bytes in their literal form. Pull-Request: #1403 Reviewed-by: Romain Chanoir Reviewed-by: Alexis Laferrière Reviewed-by: Jean Privat --- diff --git a/benchmarks/polygons/Makefile b/benchmarks/polygons/Makefile new file mode 100644 index 0000000..e6bd303 --- /dev/null +++ b/benchmarks/polygons/Makefile @@ -0,0 +1,3 @@ +all: + $(MAKE) all -C nit + $(MAKE) all -C java diff --git a/benchmarks/polygons/java/Makefile b/benchmarks/polygons/java/Makefile new file mode 100644 index 0000000..e327368 --- /dev/null +++ b/benchmarks/polygons/java/Makefile @@ -0,0 +1,19 @@ +all: add_vertex_b sort_vertices_b intersection_b convex_hull_b convexity_b contain_b + +add_vertex_b: + ./bench_polygon.sh add_vertex + +sort_vertices_b: + ./bench_polygon.sh sort_vertices + +intersection_b: + ./bench_polygon.sh intersection + +convex_hull_b: + ./bench_polygon.sh convex_hull + +convexity_b: + ./bench_polygon.sh convexity + +contain_b: + ./bench_polygon.sh contain diff --git a/benchmarks/polygons/java/bench_polygon.sh b/benchmarks/polygons/java/bench_polygon.sh new file mode 100755 index 0000000..46c2019 --- /dev/null +++ b/benchmarks/polygons/java/bench_polygon.sh @@ -0,0 +1,173 @@ +#!/bin/bash +# 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. + +source ../../bench_common.sh +source ../../bench_plot.sh + +# Default number of times a command must be run with bench_command +# Can be overrided with 'the option -n' +count=5 +points=100000 + +function usage() +{ + echo "run_bench: [options]* bench_name args" + echo " -n count: number of execution for each bar (default: $count)" + echo " -p points: number of points used for the polygons (default: $points)" + echo " -h: this help" + echo "" + echo "Benches : " + echo " add_vertex: bench adding vertex in a polygon" + echo " - usage : add_vertex nbpts" + echo " sort_vertices: sort the vertices of the polygon" + echo " - usage : sort_vertices nbpts" + echo " intersection: bench the intersection between two polygons" + echo " - usage : intersection nbpts" + echo " convex_hull: bench creating the convex hull of a set of points" + echo " - usage : convex_hull nbpts" + echo " convexity : bench the verification of the convexity of a polygon" + echo " - usage : convexity nbpts" + echo " contain : bench the point in polygon check" + echo " - usage : contain nbpts" +} + + +function bench_add_vertex() +{ + if [ -d add_vertex ]; then + rm add_vertex/* + else + mkdir add_vertex + fi + + cd add_vertex + + javac ../code/*.java -d . + + prepare_res add_vertex.out add_vertex add_vertex + + bench_command add_vertex add_vertex java BenchPolygon add_vertex $((points / 2)) +} + +function bench_sorting() +{ + if [ -d sort_vertices ]; then + rm sort_vertices/* + else + mkdir sort_vertices + fi + cd sort_vertices + + javac ../code/*.java -d . + + prepare_res sort_vertices.out sort_vertex sort_vertices + + bench_command sort_vertices sort_vertices java BenchPolygon sort_vertices $((points * 20)) + +} + +function bench_intersection() +{ + if [ -d intersection ]; then + rm intersection/* + else + mkdir intersection + fi + cd intersection + + javac ../code/*.java -d . + + prepare_res intersection.out intersection intersection + + bench_command intersection intersection java BenchPolygon intersection $((points / 10)) +} + +function bench_convex_hull() +{ + echo Bench way too long, skipping it + + return + + if [ -d convex_hull ]; then + rm convex_hull/* + else + mkdir convex_hull + fi + cd convex_hull + + javac ../code/*.java -d . + + prepare_res convex_hull.out convex_hull convex_hull + + bench_command convex_hull convex_hull java BenchPolygon convex_hull $((points * 30)) +} + +function bench_convexity() +{ + if [ -d convexity ]; then + rm convexity/* + else + mkdir convexity + fi + cd convexity + + javac ../code/*.java -d . + + prepare_res convexity.out convexity convexity + + bench_command convexity convexity java BenchPolygon convexity $((points * 40)) +} + + +function bench_contain() +{ + if [ -d contain ]; then + rm contain/* + else + mkdir contain + fi + cd contain + + javac ../code/*.java -d . + + prepare_res contain.out contain contain + + bench_command contain contain java BenchPolygon contain $((points * 50)) +} + +stop=false +while [ "$stop" = false ]; do + case "$1" in + -h) usage; exit;; + -n) count="$2"; shift; shift;; + -p) points="$2"; shift;shift;; + *) stop=true + esac +done + +if test $# -lt 1; then + usage + exit +fi + +case "$1" in + add_vertex) shift; bench_add_vertex $@ ;; + sort_vertices) shift; bench_sorting $@ ;; + intersection) shift; bench_intersection $@ ;; + convex_hull) shift; bench_convex_hull $@ ;; + convexity) shift; bench_convexity $@;; + contain) shift; bench_contain $@;; + *) usage; exit;; +esac diff --git a/benchmarks/polygons/java/code/AntiClockSort.java b/benchmarks/polygons/java/code/AntiClockSort.java new file mode 100644 index 0000000..e698d62 --- /dev/null +++ b/benchmarks/polygons/java/code/AntiClockSort.java @@ -0,0 +1,53 @@ + +/** + * + * @author Johan + * @source + * http://stackoverflow.com/questions/6989100/sort-points-in-clockwise-order + */ +public class AntiClockSort extends PolygonSorter { + + public AntiClockSort(double[][] points) { + super(points); + } + + /** + * Compare polygon vertices in counter-clock wise order starting at six + * hour. If two points share the same rad, then the farest to the center is + * chosen. + * + * @param a: a point to compare + * @param b: a second point to compare + * @return + */ + @Override + public int compare(PointDouble a, PointDouble b) { + if (a.x - center.x >= 0 && b.x - center.x < 0) { + return -1; + } + if (a.x - center.x < 0 && b.x - center.x >= 0) { + return +1; + } + if (a.x - center.x == 0 && b.x - center.x == 0) { + if (a.y - center.y >= 0 || b.y - center.y >= 0) { + return (a.y > b.y) ? -1 : +1; + } + return (b.y > a.y) ? -1 : +1; + } + + // compute the cross product of vectors (center -> a) x (center -> b) + double det = (a.x - center.x) * (b.y - center.y) - (b.x - center.x) * (a.y - center.y); + if (det < 0) { + return -1; + } + if (det > 0) { + return +1; + } + + // points a and b are on the same line from the center + // check which point is closer to the center + double d1 = (a.x - center.x) * (a.x - center.x) + (a.y - center.y) * (a.y - center.y); + double d2 = (b.x - center.x) * (b.x - center.x) + (b.y - center.y) * (b.y - center.y); + return (d1 > d2) ? -1 : +1; + } +} diff --git a/benchmarks/polygons/java/code/BenchPolygon.java b/benchmarks/polygons/java/code/BenchPolygon.java new file mode 100644 index 0000000..bb7721f --- /dev/null +++ b/benchmarks/polygons/java/code/BenchPolygon.java @@ -0,0 +1,147 @@ +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Date; +import java.util.Random; + +/** + * + * @author Johan Kayser, Romain Chanoir + */ +/** + * Runs the benchmarks for the most important operations and generates a file + * with time execution results + */ +public class BenchPolygon { + + public static void main(String[] args) throws IOException { + int n = 0; + if(args[1] != null){ + n = Integer.parseInt(args[1]); + }else { + n = 100000; + } + switch (args[0]){ + case "add_vertex": + testAddVertex(n); + break; + case "sort_vertices": + testSortVertices(n); + break; + case "intersection": + testIntersects(n); + break; + case "convex_hull": + testConvexHull(n); + break; + case "convexity": + testIsConvex(n); + break; + case "contain": + testContain(n); + break; + default: + break; + } + } + + /** + * addVertex bench: adds a vertex to a polygon with the given number of + * vertices + */ + public static void testAddVertex(int nb) throws IOException { + ArrayList points = new ArrayList<>(); + ArrayList randomPoints = new ArrayList<>(); + randomPoints = generatePoints(nb + 1); + + for (int i = 0; i < nb; ++i) { + points.add(randomPoints.remove(0)); + } + ConvexPolygon test = new ConvexPolygon(points); + test.sortVertices(new AntiClockSort(test.getVertices())); + + test.addVertex(randomPoints.remove(0)); + } + + /** + * sortVertices bench: sorts the given number of vertices in the ArrayList + * of a polygon + */ + public static void testSortVertices(int nb) throws IOException { + ArrayList randomPoints = new ArrayList<>(); + randomPoints = generatePoints(nb); + Collections.shuffle(randomPoints); + + ConvexPolygon test = new ConvexPolygon(randomPoints); + test.sortVertices(new AntiClockSort(test.getVertices())); + + } + + /** + * intersects bench: tests the intersection between two polygons with the + * given number of vertices + */ + public static void testIntersects(int nb) throws IOException { + ArrayList points1 = new ArrayList<>(); + ArrayList points2 = new ArrayList<>(); + points1 = generatePoints(nb); + points2 = generatePoints(nb); + ConvexPolygon test1 = new ConvexPolygon(points1); + ConvexPolygon test2 = new ConvexPolygon(points2); + test1.sortVertices(new AntiClockSort(test1.getVertices())); + test2.sortVertices(new AntiClockSort(test2.getVertices())); + + Boolean rez = test1.intersects(test2); + } + + /** + * convexHull bench: gets the convex hull of the given number of points + */ + public static void testConvexHull(int nb) throws IOException { + ArrayList randomPoints = new ArrayList<>(); + randomPoints = generatePoints(nb); + Collections.shuffle(randomPoints); + ConvexPolygon test = new ConvexPolygon(randomPoints); + + ConvexPolygon rez = test.convexHull(randomPoints); + } + + /** + * isConvex bench: checks if the polygon with the given number of vertices + * is convex (we test the worst case -> polygon vertices are ordered) + */ + public static void testIsConvex(int nb) throws IOException { + ArrayList randomPoints = new ArrayList<>(); + randomPoints = generatePoints(nb); + ConvexPolygon test = new ConvexPolygon(randomPoints); + test.sortVertices(new AntiClockSort(test.getVertices())); + + Boolean rez = test.isConvex(); + } + + /** + * contain bench: checks if the polygon with the given number of vertices + * contains a randomly generated point + */ + public static void testContain(int nb) throws IOException { + ArrayList randomPoints = new ArrayList<>(); + randomPoints = generatePoints(nb); + ConvexPolygon test = new ConvexPolygon(randomPoints); + test.sortVertices(new AntiClockSort(test.getVertices())); + + Boolean rez = test.contain(new PointDouble(0.0, 0.0)); + } + + /** + * generates some points making it easier to use convex polygons + */ + public static ArrayList generatePoints(int nb) { + ArrayList pts = new ArrayList<>(); + pts = PointDouble.getNPointsOnCircle(100.0, nb); + return pts; + } +} diff --git a/benchmarks/polygons/java/code/ClockSort.java b/benchmarks/polygons/java/code/ClockSort.java new file mode 100644 index 0000000..617b194 --- /dev/null +++ b/benchmarks/polygons/java/code/ClockSort.java @@ -0,0 +1,50 @@ + +/** + * + * @author Johan + */ +public class ClockSort extends PolygonSorter { + + public ClockSort(double[][] points) { + super(points); + } + + /** + * Compare polygon vertices in clock wise order starting at six hour. If two + * points share the same rad, then the farest to the center is chosen. + * + * @param a: a point to compare + * @param b: a second point to compare + * @return + */ + @Override + public int compare(PointDouble a, PointDouble b) { + if (a.x - center.x >= 0 && b.x - center.x < 0) { + return +1; + } + if (a.x - center.x < 0 && b.x - center.x >= 0) { + return -1; + } + if (a.x - center.x == 0 && b.x - center.x == 0) { + if (a.y - center.y >= 0 || b.y - center.y >= 0) { + return (a.y > b.y) ? +1 : -1; + } + return (b.y > a.y) ? +1 : -1; + } + + // compute the cross product of vectors (center -> a) x (center -> b) + double det = (a.x - center.x) * (b.y - center.y) - (b.x - center.x) * (a.y - center.y); + if (det < 0.0d) { + return +1; + } + if (det > 0.0d) { + return -1; + } + + // points a and b are on the same line from the center + // check which point is closer to the center + double d1 = (a.x - center.x) * (a.x - center.x) + (a.y - center.y) * (a.y - center.y); + double d2 = (b.x - center.x) * (b.x - center.x) + (b.y - center.y) * (b.y - center.y); + return (d1 > d2) ? +1 : -1; + } +} diff --git a/benchmarks/polygons/java/code/ConvexPolygon.java b/benchmarks/polygons/java/code/ConvexPolygon.java new file mode 100644 index 0000000..e02bc57 --- /dev/null +++ b/benchmarks/polygons/java/code/ConvexPolygon.java @@ -0,0 +1,280 @@ + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; + +/** + * + * @author romis_000, Johan + */ +public class ConvexPolygon { + + private ArrayList points = new ArrayList(); + + public ConvexPolygon(ArrayList points) { + this.points = points; + } + + public ArrayList getPointDoubles() { + return points; + } + + public double[] GetXPointDoubles() { + double xpoints[] = new double[this.points.size()]; + int c = 0; + for (PointDouble p : this.points) { + xpoints[c] = p.x; + ++c; + } + return xpoints; + } + + public double[] GetYPointDoubles() { + double ypoints[] = new double[this.points.size()]; + int c = 0; + for (PointDouble p : this.points) { + ypoints[c] = p.y; + ++c; + } + return ypoints; + } + + public double[][] getVertices() { + double[][] vertices = new double[points.size()][2]; + for (int i = 0; i < points.size(); ++i) { + vertices[i][0] = points.get(i).x; + vertices[i][1] = points.get(i).y; + } + return vertices; + } + + /** + * Returns the axis corresponding to the edges of the polygon, used to check + * for detection collision + */ + public PointDouble[] Getaxes() { + PointDouble[] axes = new PointDouble[this.points.size()]; + for (int i = 0; i < this.points.size(); i++) { + // get the current vertex + PointDouble v1 = new PointDouble(this.points.get(i).getX(), this.points.get(i).getY()); + // get the next vertex + PointDouble v2 = new PointDouble(this.points.get(i + 1 == this.points.size() ? 0 : i + 1).getX(), this.points.get(i + 1 == this.points.size() ? 0 : i + 1).getY()); + // subtract the two to get the edge vector + PointDouble edge = new PointDouble((v1.x + (-v2.x)), (v1.y + (-v2.y))); + // get either perpendicular vector + PointDouble normal = new PointDouble((-edge.y), edge.x); + // the perp method is just (x, y) => (-y, x) or (y, -x) + axes[i] = normal; + } + return axes; + } + + /** + * Checks if the polygon is convex + */ + public boolean isConvex() { + PointDouble prev = points.get(points.size() - 2); + PointDouble curr = points.get(points.size() - 1); + PointDouble next = points.get(0); + // Are the first two selected edges making a turnleft ? + boolean isCCW = turnLeft(prev, curr, next); + // Verify if all the edges are making the same type of angle as the first two + for (int i = 1; i < points.size(); i++) { + prev = curr; + curr = next; + next = points.get(i); + if (turnLeft(prev, curr, next) != isCCW) { + return false; + } + } + return true; + } + + /** + * Checks if a given point is within the polygon + */ + public boolean contain(PointDouble p) { + PointDouble prev = points.get(points.size() - 1); + PointDouble curr = p; + PointDouble next = points.get(0); + // Is the point left or right of the selected edge ? + boolean isCCW = turnLeft(prev, curr, next); + // Is the point the same side of every other edges of the polygon ? + for (int i = 1; i < points.size(); i++) { + prev = next; + next = points.get(i); + if (turnLeft(prev, curr, next) != isCCW) { + return false; + } + } + return true; + } + + /** + * Check the sign of the angle between vectors [p1, p2] and [p2, p3] + * with the cross product + */ + public boolean turnLeft(PointDouble p1, PointDouble p2, PointDouble p3) { + return ((p2.getX() - p1.getX()) * (p3.getY() + - p2.getY()) - (p3.getX() - p2.getX()) * (p2.getY() - p1.getY())) > 0; + } + + /** + * Checks if the vertices of the polygon are in counter-clock wise order + * The vertices of the polygon need to be sorted for this test + */ + public boolean isCCW() { + double min = points.get(0).getY(); + int minIndex = 0; + for (int i = 1; i < points.size() - 1; i++) { + if (points.get(i).getY() < min) { + min = points.get(i).getY(); + minIndex = i; + } + } + PointDouble prev = points.get((minIndex - 1 + points.size()) % points.size()); + PointDouble next = points.get((minIndex + 1) % points.size()); + return turnLeft(prev, points.get(minIndex), next); + } + + /** + * Calculates the convex hull of list of points + * Using the monotone chain algorithm + */ + public ConvexPolygon convexHull(ArrayList points) { + Collections.sort(points, new PointXCompare()); + int n = points.size(); + + ArrayList pl1 = new ArrayList(); + ArrayList pl2 = new ArrayList(); + for (int i = 0; i < n; i++) { + while (pl2.size() >= 2 && !(turnLeft(pl2.get(pl2.size() - 2), pl2.get(pl2.size() - 1), points.get(i)))) { + pl2.remove(pl2.get(pl2.size() - 1)); + } + pl2.add(points.get(i)); + } + for (int i = n - 1; i >= 0; i--) { + while (pl1.size() >= 2 && !(turnLeft(pl1.get(pl1.size() - 2), pl1.get(pl1.size() - 1), points.get(i)))) { + pl1.remove(pl1.get(pl1.size() - 1)); + } + pl1.add(points.get(i)); + } + pl1.remove(pl1.size() - 1); + pl2.remove(pl2.size() - 1); + pl2.addAll(pl1); + return new ConvexPolygon(pl2); + } + + /** + * Translates the polygon from the given numbers + */ + public void translate(double x, double y) { + for (PointDouble p : this.points) { + p.x += x; + p.y += y; + } + } + + /** + * Checks for an intersection between the polygon and the second given + * polygon + */ + public Boolean intersects(ConvexPolygon pol2) { + PointDouble[] axes1 = this.Getaxes(); + PointDouble[] axes2 = pol2.Getaxes(); + for (int i = 0; i < axes1.length; i++) { + PointDouble axis = axes1[i]; + // project both shapes onto the axis + Projection p1 = this.project(axis); + Projection p2 = pol2.project(axis); + // do the projections overlap? + if (!p1.overlap(p2)) { + // then we can guarantee that the shapes do not overlap + return false; + } + } + for (int i = 0; i < axes2.length; i++) { + PointDouble axis = axes2[i]; + Projection p1 = this.project(axis); + Projection p2 = pol2.project(axis); + if (!p1.overlap(p2)) { + return false; + } + } + return true; + } + + /** + * Generates a projection of an edge of the polygon on a given axis + */ + public Projection project(PointDouble axis) { + double min = ((axis.x * this.points.get(0).x) + (axis.y * this.points.get(0).y)); + double max = min; + for (int i = 1; i < this.points.size(); i++) { + double p = ((axis.x * this.points.get(i).x) + (axis.y * this.points.get(i).y)); + if (p < min) { + min = p; + } else if (p > max) { + max = p; + } + } + Projection proj = new Projection(min, max); + return proj; + } + + public Boolean hasVertex(PointDouble pt) { + for (int i = 0; i < this.points.size(); i++) { + //for (int i = 0; i < this.points.size() - 1; i++) { + if (this.points.get(i).equals(pt)) { + return true; + } + } + return false; + } + + public Boolean deleteVertex(PointDouble pt) { + if (this.points.size() > 3) { + for (int i = 0; i < this.points.size(); i++) { + if (this.points.get(i).equals(pt)) { + this.points.remove(i); + return true; + } + } + } + return false; + } + + /** + * Sorts the vertices of the polygon in an order specified by the sorter + * used + */ + public void sortVertices(PolygonSorter sorter) { + PointDouble[] arrPointDoubles = points.toArray(new PointDouble[points.size()]); + Arrays.sort(arrPointDoubles, sorter); + this.points.clear(); + points.addAll(Arrays.asList(arrPointDoubles)); + } + + /* + * Add a vertex to the polygon + * Return true if the vertex is added to the polygon + * Return false otherwise, which means that the addition + * of the vertex would have made it concave. + */ + public Boolean addVertex(PointDouble pt) { + // Make a temporary list to check some properties of the new polygon + ArrayList tempList = new ArrayList<>(Arrays.asList(this.points.toArray(new PointDouble[this.points.size()]))); + tempList.add(pt); + // Create a temporary polygon + ConvexPolygon tempPolygon = new ConvexPolygon(tempList); + // Sort it + tempPolygon.sortVertices(new AntiClockSort(tempPolygon.getVertices())); + // We need the new polygon to be convex, or we can't accept to add the new vertex. + if (tempPolygon.isConvex()) { + this.points = tempPolygon.points; + return true; + } else { + return false; + } + } +} diff --git a/benchmarks/polygons/java/code/PointDouble.java b/benchmarks/polygons/java/code/PointDouble.java new file mode 100644 index 0000000..8e1b0a4 --- /dev/null +++ b/benchmarks/polygons/java/code/PointDouble.java @@ -0,0 +1,60 @@ + +import java.util.ArrayList; +import java.util.Random; + +/** + * Represents a 2d point with double coordinates + * + * @author Johan + */ +public class PointDouble { + + double x; + double y; + + public PointDouble() { + this(0.0d, 0.0d); + } + + public PointDouble(double x, double y) { + this.x = x; + this.y = y; + } + + public double getX() { + return this.x; + } + + public double getY() { + return this.y; + } + + @Override + public boolean equals(Object obj) { + if (obj == null || getClass() != obj.getClass()) { + return false; + } + final PointDouble other = (PointDouble) obj; + if (Double.doubleToLongBits(this.x) != Double.doubleToLongBits(other.x)) { + return false; + } + if (Double.doubleToLongBits(this.y) != Double.doubleToLongBits(other.y)) { + return false; + } + return true; + } + + /** + * returns a array of n points on a circle + */ + public static ArrayList getNPointsOnCircle(double radius, int n) { + ArrayList points = new ArrayList<>(); + Random generator = new Random(0); + for(int i = 0; i < n; i++){ + double angle = generator.nextFloat() * Math.PI * 2; + PointDouble p = new PointDouble(Math.cos(angle) * radius, Math.sin(angle) * radius); + points.add(p); + } + return points; + } +} diff --git a/benchmarks/polygons/java/code/PointXCompare.java b/benchmarks/polygons/java/code/PointXCompare.java new file mode 100644 index 0000000..34f4520 --- /dev/null +++ b/benchmarks/polygons/java/code/PointXCompare.java @@ -0,0 +1,21 @@ + +import java.util.Comparator; + +/** + * + * @author romis_000 + */ +class PointXCompare + implements Comparator { + + @Override + public int compare(final PointDouble a, final PointDouble b) { + if (a.x == b.x) { + //return (int) (a.y - b.y); + return (a.y > b.y) ? -1 : +1; + } else { + //return (int)(a.x - b.x); + return (a.x > b.x) ? -1 : +1; + } + } +} diff --git a/benchmarks/polygons/java/code/PolygonSorter.java b/benchmarks/polygons/java/code/PolygonSorter.java new file mode 100644 index 0000000..e05b984 --- /dev/null +++ b/benchmarks/polygons/java/code/PolygonSorter.java @@ -0,0 +1,33 @@ + +import java.util.Comparator; + +/** + * An utility class to sort the polygon vertices, is extended by AntiClockSort + * and ClockSort + * + * @author Johan + */ +public abstract class PolygonSorter implements Comparator { + + PointDouble center; + + public PolygonSorter(double[][] podoubles) { + this.center = calcCenter(podoubles); + } + + /** + * returns the point representing the center of a polygon + */ + final PointDouble calcCenter(double[][] podoubles) { + double sumx = 0; + double sumy = 0; + for (double[] podouble : podoubles) { + sumx += podouble[0]; + sumy += podouble[1]; + } + return new PointDouble(sumx / podoubles.length, sumy / podoubles.length); + } + + @Override + public abstract int compare(PointDouble a, PointDouble b); +} diff --git a/benchmarks/polygons/java/code/Projection.java b/benchmarks/polygons/java/code/Projection.java new file mode 100644 index 0000000..e18688e --- /dev/null +++ b/benchmarks/polygons/java/code/Projection.java @@ -0,0 +1,21 @@ + +/** + * An utility class to store a projection of an edge on an axis, used by the + * intersects operation + * + * @author Johan + */ +public class Projection { + + private double min; + private double max; + + public Projection(double min, double max) { + this.min = min; + this.max = max; + } + + public Boolean overlap(Projection p2) { + return !(this.min > p2.max || p2.min > this.max); + } +} diff --git a/benchmarks/polygons/nit/Makefile b/benchmarks/polygons/nit/Makefile new file mode 100644 index 0000000..e327368 --- /dev/null +++ b/benchmarks/polygons/nit/Makefile @@ -0,0 +1,19 @@ +all: add_vertex_b sort_vertices_b intersection_b convex_hull_b convexity_b contain_b + +add_vertex_b: + ./bench_polygon.sh add_vertex + +sort_vertices_b: + ./bench_polygon.sh sort_vertices + +intersection_b: + ./bench_polygon.sh intersection + +convex_hull_b: + ./bench_polygon.sh convex_hull + +convexity_b: + ./bench_polygon.sh convexity + +contain_b: + ./bench_polygon.sh contain diff --git a/benchmarks/polygons/nit/bench_polygon.nit b/benchmarks/polygons/nit/bench_polygon.nit new file mode 100644 index 0000000..695f4aa --- /dev/null +++ b/benchmarks/polygons/nit/bench_polygon.nit @@ -0,0 +1,135 @@ +#This file is part of NIT (http://www.nitlanguage.org). +# +# Copyright 2015 Romain Chanoir +# +# 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 bench for the polygons +module bench_polygon + +intrude import geometry::polygon +import opts + +# Bench adding random vertices +fun bench_add_vertices(n: Int) do + var randompoints = generate_points(n + 1) + var points = randompoints.clone + points.remove_at(points.length -1) + var poly = new ConvexPolygon.with_vertices(randompoints) + poly.sort_ccw + poly.add_vertex(randompoints.last) +end + +# Bench the convex hull algorithm +fun bench_convex_hull(n: Int) do + srand_from(50) + var randompoints = new Array[Point[Float]] + for i in [0..n] do + var point = new Point[Float](300.0.rand, 300.0.rand) + randompoints.add(point) + end + convex_hull(randompoints) +end + + +# Bench the convexity verificatioon +fun bench_convexity(n : Int) do + var randompoints = generate_points(n) + var poly = new ConvexPolygon.with_vertices(randompoints) + poly.sort_ccw + poly.is_convex +end + +# Bench the point in polygon algorithm +fun bench_contain(n : Int) do + srand_from(50) + var randompoints = generate_points(n) + var poly = new ConvexPolygon.with_vertices(randompoints) + poly.sort_ccw + var point = new Point[Float](0.0, 0.0) + poly.contain(point) +end + +# Bench the sorting of the vertices +fun bench_sorting(n : Int) do + var randompoints = generate_points(n) + randompoints.shuffle + var poly = new ConvexPolygon.with_vertices(randompoints) + poly.sort_ccw + +end + +# Bench the intersection test between two polygons +fun bench_intersection(n : Int) do + var r1 = generate_points(n) + var r2 = generate_points(n) + var poly1 = new ConvexPolygon.with_vertices(r1) + var poly2 = new ConvexPolygon.with_vertices(r2) + poly1.sort_ccw + poly2.sort_ccw + poly1.intersects(poly2) +end + +# Get `n` points from a circle +fun get_points_on_circle(radius: Float, n: Int): Array[Point[Float]] do + srand_from(50) + var points = new Array[Point[Float]] + for i in n.times do + var angle = 1000.0.rand * pi * 2.0 + var point = new Point[Float](angle.cos * radius, angle.sin * radius) + points.add(point) + end + return points +end + +# Helper for `get_points_on_circle` +fun generate_points(n: Int): Array[Point[Float]] do + return get_points_on_circle(100.0, n) +end + +var opts = new OptionContext +var mode = new OptionEnum(["add_vertex","sort_vertices","intersection","convex_hull","is_convex","contain"], "Mode", -1, "-m") +var nb_points = new OptionInt("number of points generated for the bench", -1, "--nbpts") +opts.add_option(mode, nb_points) + +opts.parse(args) + +if nb_points.value == -1 then + opts.usage + exit(-1) +end + +var modval = mode.value +var n = nb_points.value +if modval == 0 then + print "bench_add_vertices" + bench_add_vertices(n) +else if modval == 1 then + print "bench_sorting" + bench_sorting(n) +else if modval == 2 then + print "bench_intersection" + bench_intersection(n) +else if modval == 3 then + print "bench_convex_hull" + bench_convex_hull(n) +else if modval == 4 then + print "bench_convexity" + bench_convexity(n) +else if modval == 5 then + print "bench_contain" + bench_contain(n) +else + opts.usage + exit(-1) +end diff --git a/benchmarks/polygons/nit/bench_polygon.sh b/benchmarks/polygons/nit/bench_polygon.sh new file mode 100755 index 0000000..52895e9 --- /dev/null +++ b/benchmarks/polygons/nit/bench_polygon.sh @@ -0,0 +1,168 @@ +#!/bin/bash +# 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. + +source ../../bench_common.sh +source ../../bench_plot.sh + +# Default number of times a command must be run with bench_command +# Can be overrided with 'the option -n' +count=5 +points=100000 + +function usage() +{ + echo "run_bench: [options]* bench_name args" + echo " -n count: number of execution for each bar (default: $count)" + echo " -p points: number of points used for the polygons (default: $points)" + echo " -h: this help" + echo "" + echo "Benches : " + echo " add_vertex: bench adding vertex in a polygon" + echo " - usage : add_vertex p" + echo " sort_vertices: sort the vertices of the polygon" + echo " - usage : sort_vertices p" + echo " intersection: bench the intersection between two polygons" + echo " - usage : intersection p" + echo " convex_hull: bench creating the convex hull of a set of points" + echo " - usage : convex_hull p" + echo " convexity : bench the verification of the convexity of a polygon" + echo " - usage : convexity p" + echo " contain : bench the point in polygon check" + echo " - usage : contain p" +} + + +function bench_add_vertex() +{ + if [ -d add_vertex ]; then + rm add_vertex/* + else + mkdir add_vertex + fi + cd add_vertex + + ../../../../bin/nitc --global ../bench_polygon.nit + + prepare_res add_vertex.out add_vertex add_vertex + + bench_command add_vertex add_vertex ./bench_polygon -m add_vertex --nbpts $((points / 2)) +} + +function bench_sorting() +{ + if [ -d sort_vertices ]; then + rm sort_vertices/* + else + mkdir sort_vertices + fi + cd sort_vertices + + ../../../../bin/nitc --global ../bench_polygon.nit + + prepare_res sort_vertices.out sort_vertex sort_vertices + + bench_command sort_vertices sort_vertices ./bench_polygon -m sort_vertices --nbpts $((points * 20)) +} + +function bench_intersection() +{ + if [ -d intersection ]; then + rm intersection/* + else + mkdir intersection + fi + cd intersection + + ../../../../bin/nitc --global ../bench_polygon.nit + + prepare_res intersection.out intersection intersection + + bench_command intersection intersection ./bench_polygon -m intersection --nbpts $((points / 10)) +} + +function bench_convex_hull() +{ + if [ -d convex_hull ]; then + rm convex_hull/* + else + mkdir convex_hull + fi + cd convex_hull + + ../../../../bin/nitc --global ../bench_polygon.nit + + prepare_res convex_hull.out convex_hull convex_hull + + bench_command convex_hull convex_hull ./bench_polygon -m convex_hull --nbpts $((points * 30)) +} + +function bench_convexity() +{ + if [ -d convexity ]; then + rm convexity/* + else + mkdir convexity + fi + cd convexity + + ../../../../bin/nitc --global ../bench_polygon.nit + + prepare_res convexity.out convexity convexity + + bench_command convexity convexity ./bench_polygon -m is_convex --nbpts $((points * 40)) +} + + +function bench_contain() +{ + if [ -d contain ]; then + rm contain/* + else + mkdir contain + fi + cd contain + + ../../../../bin/nitc --global ../bench_polygon.nit + + prepare_res contain.out contain contain + + bench_command contain contain ./bench_polygon -m contain --nbpts $((points * 50)) + +} + +stop=false +while [ "$stop" = false ]; do + case "$1" in + -h) usage; exit;; + -n) count="$2"; shift; shift;; + -p) points="$2"; shift;shift;; + *) stop=true + esac +done + +if test $# -lt 1; then + usage + exit +fi + +case "$1" in + add_vertex) shift; bench_add_vertex $@ ;; + sort_vertices) shift; bench_sorting $@ ;; + intersection) shift; bench_intersection $@ ;; + convex_hull) shift; bench_convex_hull $@ ;; + convexity) shift; bench_convexity $@;; + contain) shift; bench_contain $@;; + *) usage; exit;; +esac diff --git a/lib/a_star.nit b/lib/a_star.nit index a0b1b48..9780e12 100644 --- a/lib/a_star.nit +++ b/lib/a_star.nit @@ -211,7 +211,7 @@ end # Link between two nodes and associated to a graph class Link - auto_serializable + serialize # Type of the nodes in `graph` type N: Node @@ -287,7 +287,7 @@ end # Result from path finding and a walkable path class AStarPath[N] - auto_serializable + serialize # Total cost of this path var total_cost: Int @@ -317,7 +317,7 @@ end # Context related to an evocation of pathfinding class PathContext - auto_serializable + serialize # Type of the nodes in `graph` type N: Node @@ -352,7 +352,7 @@ end # Warning: A* is not optimize for such a case class ConstantPathContext super PathContext - auto_serializable + serialize redef fun worst_cost do return 1 redef fun cost(l) do return 1 @@ -364,7 +364,7 @@ end # A `PathContext` for graphs with `WeightedLink` class WeightedPathContext super PathContext - auto_serializable + serialize redef type L: WeightedLink @@ -393,7 +393,7 @@ end # A `Link` with a `weight` class WeightedLink super Link - auto_serializable + serialize # The `weight`, or cost, of this link var weight: Int @@ -401,7 +401,7 @@ end # Advanced path conditions with customizable accept states class TargetCondition[N: Node] - auto_serializable + serialize # Should the pathfinding accept `node` as a goal? fun accept(node: N): Bool is abstract diff --git a/lib/android/bundle/bundle.nit b/lib/android/bundle/bundle.nit index fde88af..edb0c88 100644 --- a/lib/android/bundle/bundle.nit +++ b/lib/android/bundle/bundle.nit @@ -503,7 +503,7 @@ class Bundle # Retrieve an `Object` serialized via `[]=` function # Returns `null` if there's no serialized object corresponding to the given key # or if it's the wrong value type - # Make sure that the serialized object is `auto_serializable` or that it + # Make sure that the serialized object is `serialize` or that it # redefines the appropriate methods. Refer to `Serializable` documentation # for further details fun deserialize(key: String): nullable Object @@ -520,7 +520,7 @@ class Bundle # Retrieve an `Array` of `Object` serialized via `[]=` function # Returns `null` if there's no serialized `Array` corresponding to the given key # or if it's the wrong value type - # Make sure that the serialized objects are `auto_serializable` or that they + # Make sure that the serialized objects are `serialize` or that they # redefine the appropriate methods. Refer to `Serializable` documentation # for further details fun deserialize_array(key: String): nullable Array[nullable Object] diff --git a/lib/android/shared_preferences/shared_preferences_api10.nit b/lib/android/shared_preferences/shared_preferences_api10.nit index d4e71a8..ca3a2b9 100644 --- a/lib/android/shared_preferences/shared_preferences_api10.nit +++ b/lib/android/shared_preferences/shared_preferences_api10.nit @@ -390,7 +390,7 @@ class SharedPreferences # Retrieve an `Object` stored via `[]=` function # # Returns `null` if there's no serialized object corresponding to the given key - # Make sure that the serialized object is `auto_serializable` or that it redefines + # Make sure that the serialized object is `serialize` or that it redefines # the appropriate methods. Refer to `Serializable` documentation for further details fun [](key: String): nullable Object do diff --git a/lib/bucketed_game.nit b/lib/bucketed_game.nit index a621c54..ad79e6c 100644 --- a/lib/bucketed_game.nit +++ b/lib/bucketed_game.nit @@ -20,13 +20,12 @@ # # Allows for fast support of a large number of entities with rare actions, # such as a forest with many individual trees. -module bucketed_game +module bucketed_game is serialize import serialization # Something acting on the game class Turnable[G: Game] - auto_serializable # Execute `turn` for this instance. fun do_turn(turn: GameTurn[G]) is abstract @@ -35,7 +34,6 @@ end # Something acting on the game from time to time class Bucketable[G: Game] super Turnable[G] - auto_serializable private var act_at: nullable Int = null @@ -49,7 +47,6 @@ end # Optimized organization of `Bucketable` instances class Buckets[G: Game] super Turnable[G] - auto_serializable # Bucket type used in this implementation. type BUCKET: HashSet[Bucketable[G]] @@ -118,12 +115,10 @@ end # Event raised at the first turn class FirstTurnEvent super GameEvent - auto_serializable end # Game logic on the client class ThinGame - auto_serializable # Game tick when `self` should act. # @@ -133,7 +128,6 @@ end # Game turn on the client class ThinGameTurn[G: ThinGame] - auto_serializable # Game tick when `self` should act. var tick: Int is protected writable @@ -145,7 +139,6 @@ end # Game turn on the full logic class GameTurn[G: Game] super ThinGameTurn[G] - auto_serializable # Game that `self` belongs to. var game: G @@ -173,7 +166,6 @@ end # Full game logic class Game super ThinGame - auto_serializable # Game type used in this implementation. type G: Game diff --git a/lib/geometry/polygon.nit b/lib/geometry/polygon.nit new file mode 100644 index 0000000..8fc1969 --- /dev/null +++ b/lib/geometry/polygon.nit @@ -0,0 +1,426 @@ +# This file is part of NIT (http://www.nitlanguage.org). +# +# Copyright 2015 Romain Chanoir +# +# 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. + +# Convex Polygons manipulations +module polygon + +import points_and_lines + +# Convex Polygon class +class ConvexPolygon + + # Vertices of this polygon + var points = new Array[Point[Float]] + + # Init this polygon with a list of `points` + # REQUIRE `pts.length == 3` + init with_vertices(pts: Array[Point[Float]]) do + assert pts.length >= 3 + points.add_all(pts) + end + + # Get an array of the x coordinates of the vertices + private fun x_coordinates: Array[Float] do + return [for p in points do p.x] + end + + # Get an array of the y coordinates of the vertices + private fun y_coordinates: Array[Float] do + return [for p in points do p.y] + end + + # Get a matrice containing the coordinates of the vertices + private fun vertices: Array[Array[Float]] do + var vertices = new Array[Array[Float]] + for i in [0..points.length[ do + var temp = new Array[Float] + temp.add(points[i].x) + temp.add(points[i].y) + vertices.add(temp) + end + return vertices + end + + # Returns the axes corresponding to the edges of the polygon, used for collision detection + private fun axes: Array[Point[Float]] do + var axes = new Array[Point[Float]] + for i in [0..points.length[ do + var p1 = new Point[Float](points[i].x, points[i].y) + var p2 = new Point[Float](points[(i+1) % points.length].x, points[(i+1) % points.length].y) + var edge = new Point[Float](p1.x - p2.x, p1.y - p2.y) + var normal = new Point[Float](-edge.y, edge.x) + axes[i] = normal + end + return axes + end + + # Sort the vertices in counter clockwise order + # + # ~~~ + # var p1 = new Point[Float](0.0, 0.0) + # var p2 = new Point[Float](5.0, 0.0) + # var p3 = new Point[Float](0.0, 5.0) + # var p4 = new Point[Float](5.0, 5.0) + # var arr = new Array[Point[Float]].with_items(p1, p2, p3, p4) + # var poly = new ConvexPolygon.with_vertices(arr) + # poly.sort_ccw + # assert poly.points == [p4, p2, p1, p3] + # ~~~ + fun sort_ccw do + var sorter = new CounterClockWiseSort.with_center(vertices) + sorter.sort(points) + end + + # Sort the vertices in clockwise order + # + # ~~~ + # var p1 = new Point[Float](0.0, 0.0) + # var p2 = new Point[Float](5.0, 0.0) + # var p3 = new Point[Float](0.0, 5.0) + # var p4 = new Point[Float](5.0, 5.0) + # var arr = new Array[Point[Float]].with_items(p1, p2, p3, p4) + # var poly = new ConvexPolygon.with_vertices(arr) + # poly.sort_cw + # assert poly.points == [p3, p1, p2, p4] + # ~~~ + fun sort_cw do + var sorter = new ClockWiseSort.with_center(vertices) + sorter.sort(points) + end + + # Does this polygon intersects `other` ? + # + # ~~~ + # var p1 = new Point[Float](0.0, 0.0) + # var p2 = new Point[Float](5.0, 0.0) + # var p3 = new Point[Float](0.0, 5.0) + # var p4 = new Point[Float](5.0, 5.0) + # var arr = new Array[Point[Float]].with_items(p1, p2, p3, p4) + # var poly = new ConvexPolygon.with_vertices(arr) + # poly.sort_ccw + # p1 = new Point[Float](2.5, 2.5) + # p2 = new Point[Float](7.5, 2.5) + # p3 = new Point[Float](2.5, 7.5) + # p4 = new Point[Float](7.5, 7.5) + # arr = new Array[Point[Float]].with_items(p1, p2, p3, p4) + # var poly2 = new ConvexPolygon.with_vertices(arr) + # poly2.sort_ccw + # assert poly.intersects(poly2) + # ~~~ + fun intersects(other: ConvexPolygon): Bool do + assert is_convex + + var axes1 = axes + var axes2 = other.axes + for axis in axes1 do + var project1 = project(axis) + var project2 = other.project(axis) + if not project1.overlap(project2) then return false + end + for axis in axes2 do + var project1 = project(axis) + var project2 = other.project(axis) + if not project1.overlap(project2) then return false + end + return true + end + + # Generate a projection of an edge of the polygon on a given axis + private fun project(axis: Point[Float]): Projection do + var min = axis.x * points[0].x + axis.y * points[0].y + var max = min + for i in [0..points.length[ do + var p = axis.x * points[i].x + axis.y * points[i].y + if p < min then min = p + if p > max then max = p + end + var projection = new Projection(min, max) + return projection + end + + # Is this polygon convex ? + # + # ~~~ + # var p1 = new Point[Float](0.0, 0.0) + # var p2 = new Point[Float](5.0, 0.0) + # var p3 = new Point[Float](0.0, 5.0) + # var p4 = new Point[Float](5.0, 5.0) + # var arr = new Array[Point[Float]].with_items(p1, p2, p3, p4) + # var poly = new ConvexPolygon.with_vertices(arr) + # poly.sort_ccw + # assert poly.is_convex + # ~~~ + fun is_convex: Bool do + var prev = points[points.length - 2] + var curr = points[points.length - 1] + var next = points[0] + var is_ccw = turn_left(prev, curr, next) + for i in [1..points.length[ do + prev = curr + curr= next + next = points[i] + if turn_left(prev ,curr, next) != is_ccw then return false + end + return true + end + + # Check if `p` is in the polygon + # + # ~~~ + # var p1 = new Point[Float](0.0, 0.0) + # var p2 = new Point[Float](5.0, 0.0) + # var p3 = new Point[Float](0.0, 5.0) + # var p4 = new Point[Float](5.0, 5.0) + # var p5 = new Point[Float](2.5, 2.5) + # var arr = new Array[Point[Float]].with_items(p1, p2, p3, p4) + # var poly = new ConvexPolygon.with_vertices(arr) + # poly.sort_ccw + # assert poly.contain(p5) + # ~~~ + fun contain(p : Point[Float]): Bool do + var prev = points[points.length - 1] + var curr = p + var next = points[0] + var is_ccw = turn_left(prev, curr, next) + for i in [1..points.length[ do + prev = next + next = points[i] + if turn_left(prev, curr, next) != is_ccw then return false + end + return true + end + + # Check if the order of the points in the polygon is counter-clockwise + # The vertices in the polygon need to be sorted + # + # ~~~ + # var p1 = new Point[Float](0.0, 0.0) + # var p2 = new Point[Float](5.0, 0.0) + # var p3 = new Point[Float](0.0, 5.0) + # var p4 = new Point[Float](5.0, 5.0) + # var arr = new Array[Point[Float]].with_items(p1, p2, p3, p4) + # var poly = new ConvexPolygon.with_vertices(arr) + # poly.sort_ccw + # assert poly.is_ccw + # ~~~ + fun is_ccw: Bool do + var min = points[0].y + var min_index = 0 + for i in [1..points.length - 1[ do + if points[i].y < min then + min = points[i].y + min_index = i + end + end + var prev = points[(min_index - 1 + points.length) % points.length] + var next = points[(min_index + 1) % points.length] + return not turn_left(prev, points[min_index], next) + end + + # Remove `p` from the vertices, keeping at least 3 vertices + fun delete_vertex(p: Point[Float]) do + if points.length > 3 then + points.remove(p) + end + end + + # Add a vertex to the polygon + # + # ~~~ + # var p1 = new Point[Float](0.0, 0.0) + # var p2 = new Point[Float](5.0, 0.0) + # var p3 = new Point[Float](0.0, 5.0) + # var p4 = new Point[Float](5.0, 5.0) + # var arr = new Array[Point[Float]].with_items(p1, p2, p3, p4) + # var poly = new ConvexPolygon.with_vertices(arr) + # var p5 = new Point[Float](2.5, 7.5) + # assert poly.add_vertex(p5) + # ~~~ + fun add_vertex(p: Point[Float]): Bool do + assert points.length >= 3 + var temp_list = points.clone + temp_list.add(p) + var temp_polygon = new ConvexPolygon.with_vertices(temp_list) + temp_polygon.sort_ccw + if temp_polygon.is_convex then + points = temp_polygon.points + return true + else + return false + end + end +end + +# Projection of an edge of a `ConvexPolygon` used for intersection test +private class Projection + var min: Float is writable + var max: Float is writable + + fun overlap(other: Projection): Bool do + return not (min > other.max or other.min > max) + end +end + +private class PointXCompare + super Comparator + + redef type COMPARED: Point[Float] + + redef fun compare(a,b : COMPARED): Int do + if a.x == b.x then + if a.y == b.y then return 0 + if a.y > b.y then return - 1 + return 1 + else + if a.x > b.x then return -1 + return 1 + end + end +end + +# Sorter for polygon vertices +private abstract class PolygonSorter + super Comparator + + redef type COMPARED: Point[Float] + + # Center of the polygon's points + var center: COMPARED + + # init calculating the center + init with_center(pts : Array[Array[Float]]) do + center = calc_center(pts) + end + + # Calculate the center + fun calc_center(pts : Array[Array[Float]]): COMPARED do + var sumx = 0.0 + var sumy = 0.0 + for ap in pts do + sumx += ap[0] + sumy += ap[1] + end + return new Point[Float](sumx / pts.length.to_f, sumy / pts.length.to_f) + end +end + +# Sort the vertices of a polygon in counter clockwise order +private class CounterClockWiseSort + super PolygonSorter + + redef fun compare(a,b: COMPARED): Int do + if a.x == b.x and a.y == b.y then return 0 + if a.x - center.x >= 0.0 and b.x - center.x < 0.0 then return -1 + if a.x - center.x < 0.0 and b.x - center.x >= 0.0 then return 1 + if a.x - center.x == 0.0 and b.x - center.x == 0 then + if a.y - center.y >= 0.0 or b.y - center.y >= 0.0 then + if a.y > b.y then return -1 + return 1 + end + if b.y > a.y then return -1 + return 1 + end + + var det = (a.x - center.x) * (b.y - center.y) - (b.x - center.x) * (a.y - center.y) + if det > 0.0 then return 1 + if det < 0.0 then return -1 + + var d1 = (a.x - center.x) * (a.x - center.x) + (a.y - center.y) * (a.y - center.y) + var d2 = (b.x - center.x) * (b.x - center.x) + (b.y - center.y) * (b.y - center.y) + if d1 > d2 then return -1 + return 1 + end +end + +# Sort the vertices of a polygon in clockwise order +private class ClockWiseSort + super PolygonSorter + + redef fun compare(a,b: COMPARED): Int do + if a.x == b.x and a.y == b.y then return 0 + if a.x - center.x >= 0.0 and b.x - center.x < 0.0 then return 1 + if a.x - center.x < 0.0 and b.x - center.x >= 0.0 then return -1 + if a.x - center.x == 0.0 and b.x - center.x == 0 then + if a.y - center.y >= 0.0 or b.y - center.y >= 0.0 then + if a.y > b.y then return 1 + return -1 + end + if b.y > a.y then return 1 + return -1 + end + + var det = (a.x - center.x) * (b.y - center.y) - (b.x - center.x) * (a.y - center.y) + if det > 0.0 then return -1 + if det < 0.0 then return 1 + + var d1 = (a.x - center.x) * (a.x - center.x) + (a.y - center.y) * (a.y - center.y) + var d2 = (b.x - center.x) * (b.x - center.x) + (b.y - center.y) * (b.y - center.y) + if d1 > d2 then return 1 + return -1 + end +end + + +# Get the convex hull of the set of `points` +# +# ~~~ +# var p1 = new Point[Float](0.0, 0.0) +# var p2 = new Point[Float](5.0, 0.0) +# var p3 = new Point[Float](0.0, 5.0) +# var p4 = new Point[Float](5.0, 5.0) +# var p5 = new Point[Float](2.5, 2.5) +# var arr = new Array[Point[Float]].with_items(p1, p2, p3, p4, p5) +# var poly = convex_hull(arr) +# assert poly.points == [p4, p3, p1, p2] +# ~~~ +fun convex_hull(points: Array[Point[Float]]): ConvexPolygon do + var sorter = new PointXCompare + sorter.sort(points) + var l = points.length + + var pl1 = new Array[Point[Float]] + var pl2 = new Array[Point[Float]] + for i in [0..l[ do + while pl2.length >= 2 and not turn_left(pl2[pl2.length - 2], pl2[pl2.length - 1], points[i]) do + pl2.remove(pl2.last) + end + pl2.add(points[i]) + end + var i = l - 1 + while i >= 0 do + while pl1.length >= 2 and not turn_left(pl1[pl1.length - 2], pl1[pl1.length - 1], points[i]) do + pl1.remove(pl1.last) + end + pl1.add(points[i]) + i-= 1 + end + pl1.remove_at(pl1.length - 1) + pl2.remove_at(pl2.length -1) + pl2.add_all(pl1) + return new ConvexPolygon.with_vertices(pl2) +end + +# Is the angle between [p1,p2] and [p2,p3] going left (counter clockwise) or right (clockwise) ? +# +# ~~~ +# var p1 = new Point[Float](0.0, 0.0) +# var p2 = new Point[Float](5.0, 0.0) +# var p3 = new Point[Float](0.0, 5.0) +# assert turn_left(p1, p2, p3) +# ~~~ +fun turn_left(p1, p2, p3: Point[Float]): Bool do + return ((p2.x - p1.x) * (p3.y - p2.y) - (p3.x - p2.x) * (p2.y - p1.y)) > 0.0 +end diff --git a/lib/json/serialization.nit b/lib/json/serialization.nit index 4b7cb15..359acf5 100644 --- a/lib/json/serialization.nit +++ b/lib/json/serialization.nit @@ -39,7 +39,7 @@ # import json::serialization # # class Person -# auto_serializable +# serialize # # var name: String # var year_of_birth: Int diff --git a/lib/more_collections.nit b/lib/more_collections.nit index 4f75430..019dc67 100644 --- a/lib/more_collections.nit +++ b/lib/more_collections.nit @@ -13,7 +13,7 @@ # limitations under the License. # Highly specific, but useful, collections-related classes. -module more_collections +module more_collections is serialize import serialization @@ -32,7 +32,6 @@ import serialization # assert m["four"] == ['i', 'i', 'i', 'i'] # assert m["zzz"] == new Array[Char] class MultiHashMap[K, V] - auto_serializable super HashMap[K, Array[V]] # Add `v` to the array associated with `k`. @@ -64,7 +63,6 @@ end # assert hm2[2, "not-two"] == null # ~~~~ class HashMap2[K1, K2, V] - auto_serializable private var level1 = new HashMap[K1, HashMap[K2, V]] @@ -113,7 +111,6 @@ end # assert hm3[2, "not-two", 22] == null # ~~~~ class HashMap3[K1, K2, K3, V] - auto_serializable private var level1 = new HashMap[K1, HashMap2[K2, K3, V]] @@ -193,7 +190,6 @@ end # assert dma.default == [65] # ~~~~ class DefaultMap[K, V] - auto_serializable super HashMap[K, V] # The default value. diff --git a/lib/serialization/README.md b/lib/serialization/README.md index 4cbcf64..ef8c445 100644 --- a/lib/serialization/README.md +++ b/lib/serialization/README.md @@ -1,11 +1,11 @@ # Abstract serialization services -The serialization services are centered around the `auto_serializable` annotation, +The serialization services are based on the `serialize` and the `noserialize` annotations, the `Serializable` interface and the implementations of `Serializer` and `Deserializer`. -## The `auto_serializable` annotation +## The `serialize` annotation -A class annotated with `auto_serializable` identifies it as a subclass of Serializable and +A class annotated with `serialize` identifies it as a subclass of Serializable and triggers the generation of customized serialization and deserialization services. ~~~ @@ -13,7 +13,7 @@ import serialization # Simple serializable class identifying a human class Person - auto_serializable + serialize # First and last name var name: String @@ -31,19 +31,19 @@ By definition of a serializable class, an instance can be serialized to a stream The deserialized instance will not be the same instance, but they should be equal. So, in this case, we can compare both instances with `==` to test their equality. -Some conditions applies to the classes that can be annotated as `auto_serializable`. +Some conditions applies to the classes that can be annotated as `serialize`. All attributes of the class must be serializable, runtime errors will be raised when trying to serialize non-serializable attributes. In the class `Person`, all attributes are typed with classes the standards library. These common types are defined defined as serializable by this project. -The attributes could also be typed with user-defined `auto_serializable` +The attributes could also be typed with user-defined `serialize` classes or any other subclass of `Serializable`. ~~~ -# This `auto_serializable` class is composed of two `auto_serializable` attributes +# This `serialize` class is composed of two `serialize` attributes class Partnership - auto_serializable + serialize var partner_a: Person var partner_b: Person @@ -53,14 +53,59 @@ class Partnership end ~~~ -The `auto_serializable` applies only to the class definition, -only attributes declared locally will be serialized. -However, each definition of a class (a refinement or specialization) -can declare `auto_serializable`. +### Scope of the `serialize` annotation + +`serialize` can annotate class definitions, modules and attributes: + +* The annotation on a class applies only to the class definition, + only attributes declared locally will be serialized. + However, each definition of a class (a refinement or specialization) can be annotated with `serialize`. + +* A module declaration annotated with `serialize` states that all its class definitions + and locally declared attributes are serializable. + + ~~~ + module shared_between_clients is serialize + ~~~ + +* Attribute annotated with `serialize` states that it is to be serialized, when the rest of the class does not. + The class will become subclass to `Serializable` but its attributes are not to be serialized by default. + Only the attributes with the `serialize` annotation will be serialized. + + ~~~ + # Only serialize the `name` + class UserCredentials + var name: String is serialize + var avatar_path: String = "/somepath/"+name is lazy + end + ~~~ + +## The `noserialize` annotation + +The `noserialize` annotation mark an exception in a `serialize` module or class definition. + +* By default a module is `noserialize`. There is no need to declare it as such. + +* A class definition annotated with `noserialize` within a `serialize` module will not be made serializable. + +* A `noserialize` attribute within a class or module annotated with `serialize` will not serialize this attribute. + The class will still be made subclass of `Serializable` and it won't affect the other attributes. + The `noserialize` attribute will not be set at deserialization. + Usually, it will also be annotated with `lazy` to get its value by another mean after the object has been deserialized. + + ~~~ + # Once again, only serialize the `name` + class UserCredentials + serialize + + var name: String + var avatar_path: String = "/somepath/"+name is noserialize, lazy + end + ~~~ ## Custom serializable classes -The annotation `auto_serializable` should be enough for most cases, +The annotation `serialize` should be enough for most cases, but in some cases you need more control over the serialization process. For more control, create a subclass to `Serializable` and redefine `core_serialize_to`. @@ -72,7 +117,7 @@ The method should only act on known class names, and call super otherwise. ### Example: the User class -The following example cannot use the `auto_serializable` annotations +The following example cannot use the `serialize` annotations because some of the arguments to the `User` class need special treatment: * The `name` attribute is perfectly normal, it can be serialized and deserialized @@ -160,7 +205,7 @@ information on the services to redefine. ## Serialization services -The `auto_serializable` annotation and the `Serializable` class are used on +The `serialize` annotation and the `Serializable` class are used on classes specific to the business domain. To write (and read) instances of these classes to a persistent format you must use implementations of `Serializer` and `Deserializer`. @@ -198,7 +243,7 @@ The serialization has some limitations: * Not enough classes from the standard library are supported. This only requires someone to actually code the support. It should not be especially hard for most classes, some can - simply declare the `auto_serializable` annotation. + simply declare the `serialize` annotation. * A limitation of the Json parser prevents deserializing from files with more than one object. @@ -206,9 +251,9 @@ The serialization has some limitations: serialize a single object to each filesand use different instances of serializer and deserializer each time. -* The `auto_serializable` annotation does not handle very well +* The `serialize` annotation does not handle very well complex constructors. This could be improved in the compiler. - For now, you may prefer to use `auto_serializable` on simple classes, + For now, you may prefer to use `serialize` on simple classes, of by using custom `Serializable`. * The serialization uses only the short name of a class, not its qualified name. diff --git a/lib/serialization/serialization.nit b/lib/serialization/serialization.nit index 8977baa..ca60d7a 100644 --- a/lib/serialization/serialization.nit +++ b/lib/serialization/serialization.nit @@ -16,7 +16,7 @@ # Abstract services to serialize Nit objects to different formats # -# This module declares the `auto_serializable` annotation to mark Nit classes as serializable. +# This module declares the `serialize` annotation to mark Nit classes as serializable. # For an introduction to this service, refer to the documentation of the `serialization` group. # This documentation provides more technical information on interesting entitie of this module. # @@ -44,6 +44,8 @@ # `notify_of_creation` must be redefined. module serialization is new_annotation auto_serializable + new_annotation serialize + new_annotation noserialize end # Abstract serialization service to be sub-classed by specialized services. diff --git a/share/nitdoc/css/nitdoc.css b/share/nitdoc/css/nitdoc.css index e47f3aa..01da471 100644 --- a/share/nitdoc/css/nitdoc.css +++ b/share/nitdoc/css/nitdoc.css @@ -81,9 +81,6 @@ article.nospace { color: #666; } -#sidebar .panel-body ul .list-labeled>li { -} - #sidebar .panel-body ul ul ul>li { font-size: 13px; color: #999; diff --git a/src/doc/console_templates/console_templates.nit b/src/doc/console_templates/console_templates.nit index 45bc33e..e94a388 100644 --- a/src/doc/console_templates/console_templates.nit +++ b/src/doc/console_templates/console_templates.nit @@ -81,11 +81,6 @@ redef class ConcernSection end end -redef class ConstructorsSection - redef var cs_title = "Constructors" - redef var cs_subtitle = null -end - redef class MEntityComposite redef var cs_title is lazy do return mentity.cs_name redef var cs_subtitle is lazy do return mentity.cs_namespace diff --git a/src/doc/doc_base.nit b/src/doc/doc_base.nit index 8f0467d..4338eee 100644 --- a/src/doc/doc_base.nit +++ b/src/doc/doc_base.nit @@ -75,6 +75,15 @@ class DocPage var root = new DocRoot redef fun to_s do return title + + # Pretty prints the content of this page. + fun pretty_print: Writable do + var res = new Template + res.addn "page: {title}" + res.addn "" + root.pretty_print_in(res) + return res + end end # `DocPage` elements that can be nested in another. @@ -91,6 +100,19 @@ abstract class DocComposite # Parent element. var parent: nullable DocComposite = null is writable + # Element uniq id. + # + # The `id` is used as name for the generated element (if any). + # Because multiple elements can be generated in the same container + # it should be uniq. + # + # The `id` can also be used to establish links between elements + # (HTML links, HTML anchors, vim links, etc.). + var id: String is writable + + # Item title if any. + var title: nullable String + # Does `self` have a `parent`? fun is_root: Bool do return parent == null @@ -99,8 +121,18 @@ abstract class DocComposite # Children are ordered, this order can be changed by the `DocPhase`. var children = new Array[DocComposite] - # Does `self` have `children`? - fun is_empty: Bool do return children.is_empty + # Is `self` not displayed in the page. + # + # By default, empty elements are hidden. + fun is_hidden: Bool do return children.is_empty + + # Title used in table of content if any. + var toc_title: nullable String is writable, lazy do return title + + # Is `self` hidden in the table of content? + var is_toc_hidden: Bool is writable, lazy do + return toc_title == null or is_hidden + end # Add a `child` to `self`. # @@ -115,6 +147,20 @@ abstract class DocComposite if parent == null then return 0 return parent.depth + 1 end + + # Pretty prints this composite recursively. + fun pretty_print: Writable do + var res = new Template + pretty_print_in(res) + return res + end + + # Appends the Pretty print of this composite in `res`. + private fun pretty_print_in(res: Template) do + res.add "#" * depth + res.addn " {id}" + for child in children do child.pretty_print_in(res) + end end # The `DocComposite` element that contains all the other. @@ -122,8 +168,12 @@ end # The root uses a specific subclass to provide different a different behavior # than other `DocComposite` elements. class DocRoot + noautoinit super DocComposite + redef var id = "" + redef var title = "" + # No op for `RootSection`. redef fun parent=(p) do end end diff --git a/src/doc/doc_phases/doc_console.nit b/src/doc/doc_phases/doc_console.nit index f927fd9..4c0c193 100644 --- a/src/doc/doc_phases/doc_console.nit +++ b/src/doc/doc_phases/doc_console.nit @@ -140,7 +140,7 @@ interface NitxQuery # Pretty prints the results for the console. fun make_results(nitx: Nitx, results: Array[NitxMatch]): DocPage do var page = new DocPage("results", "Results") - page.root.add_child(new QueryResultArticle(self, results)) + page.root.add_child(new QueryResultArticle("results.article", "Results", self, results)) return page end @@ -215,8 +215,8 @@ class CommentQuery if len == 1 then var res = results.first.as(MEntityMatch) var mentity = res.mentity - var page = new DocPage("resultats", "Results") - var article = new DefinitionArticle(mentity) + var page = new DocPage("results", "Results") + var article = new DefinitionArticle("results.article", "Results", mentity) article.cs_title = mentity.name article.cs_subtitle = mentity.cs_declaration page.root.add_child article @@ -389,7 +389,7 @@ class CodeQuery redef fun make_results(nitx, results) do var page = new DocPage("results", "Code Results") for res in results do - page.add new CodeQueryArticle(self, res.as(CodeMatch)) + page.add new CodeQueryArticle("results.article", "Results", self, res.as(CodeMatch)) end return page end diff --git a/src/doc/doc_phases/doc_graphs.nit b/src/doc/doc_phases/doc_graphs.nit index 1339d09..50a2aab 100644 --- a/src/doc/doc_phases/doc_graphs.nit +++ b/src/doc/doc_phases/doc_graphs.nit @@ -73,7 +73,7 @@ redef class MModulePage end end op.append("\}\n") - return new GraphArticle(mentity, name, "Importation Graph", op) + return new GraphArticle("{mentity.nitdoc_id}.graph", "Importation Graph", name, op) end end @@ -107,7 +107,7 @@ redef class MClassPage end end op.append("\}\n") - return new GraphArticle(mentity, name, "Inheritance Graph", op) + return new GraphArticle("{mentity.nitdoc_id}.graph", "Inheritance Graph", name, op) end end @@ -116,16 +116,14 @@ end # The graph is stored in dot format. # The final output is delayed untill rendering. class GraphArticle - super MEntityComposite + super DocArticle # Graph ID (used for outputing file with names). - var id: String - - # Graph title to display. - var graph_title: String + var graph_id: String # Dot script of the graph. var dot: Text - redef var is_empty = false + redef var is_hidden = false + redef var is_toc_hidden = true end diff --git a/src/doc/doc_phases/doc_hierarchies.nit b/src/doc/doc_phases/doc_hierarchies.nit index eecc95b..fa9de2d 100644 --- a/src/doc/doc_phases/doc_hierarchies.nit +++ b/src/doc/doc_phases/doc_hierarchies.nit @@ -40,14 +40,15 @@ end redef class MModulePage redef fun build_inh_list(v, doc) do - var section = new ImportationListSection(mentity) - var group = new PanelGroup("List") + var id = mentity.nitdoc_id + var section = new TabbedGroup("{id}.importation", "Dependencies") + var group = new PanelGroup("list.group", "List") var imports = self.imports.to_a v.name_sorter.sort(imports) - group.add_child new HierarchyListArticle(mentity, "Imports", imports) + group.add_child new MEntitiesListArticle("{id}.imports", "Imports", imports) var clients = self.clients.to_a v.name_sorter.sort(clients) - group.add_child new HierarchyListArticle(mentity, "Clients", clients) + group.add_child new MEntitiesListArticle("{id}.clients", "Clients", clients) section.add_child group section.parent = root.children.first root.children.first.children.insert(section, 1) @@ -56,45 +57,23 @@ end redef class MClassPage redef fun build_inh_list(v, doc) do - var section = new InheritanceListSection(mentity) - var group = new PanelGroup("List") + var id = mentity.nitdoc_id + var section = new TabbedGroup("{id}.inheritance", "Inheritance") + var group = new PanelGroup("list.group", "List") var parents = self.parents.to_a v.name_sorter.sort(parents) - group.add_child new HierarchyListArticle(mentity, "Parents", parents) + group.add_child new MEntitiesListArticle("{id}.parents", "Parents", parents) var ancestors = self.ancestors.to_a v.name_sorter.sort(ancestors) - group.add_child new HierarchyListArticle(mentity, "Ancestors", ancestors) + group.add_child new MEntitiesListArticle("{id}.ancestors", "Ancestors", ancestors) var children = self.children.to_a v.name_sorter.sort(children) - group.add_child new HierarchyListArticle(mentity, "Children", children) + group.add_child new MEntitiesListArticle("{id}.children", "Children", children) var descendants = self.descendants.to_a v.name_sorter.sort(descendants) - group.add_child new HierarchyListArticle(mentity, "Descendants", descendants) + group.add_child new MEntitiesListArticle("{id}.descendants", "Descendants", descendants) section.add_child group section.parent = root.children.first root.children.first.children.insert(section, 1) end end - -# FIXME diff hack -class ImportationListSection - super TabbedGroup - super MEntityComposite -end - -# FIXME diff hack -class InheritanceListSection - super TabbedGroup - super MEntityComposite -end - -# Dislay a hierarchical list of mentities. -class HierarchyListArticle - super MEntityArticle - - # Title displayed in the top of this list. - var list_title: String - - # MEntities to display in this list. - var mentities: Array[MEntity] -end diff --git a/src/doc/doc_phases/doc_html.nit b/src/doc/doc_phases/doc_html.nit index 0c843bb..83a2cc9 100644 --- a/src/doc/doc_phases/doc_html.nit +++ b/src/doc/doc_phases/doc_html.nit @@ -372,7 +372,7 @@ redef class MClassPage if not mprop_is_local(mprop) then classes.add "inherit" var cls_url = mprop.intro.mclassdef.mclass.nitdoc_url - var def_url = "{cls_url}#article:{mprop.nitdoc_id}.definition" + var def_url = "{cls_url}#{mprop.nitdoc_id}.definition" var lnk = new Link(def_url, mprop.html_name) var mdoc = mprop.intro.mdoc_or_fallback if mdoc != null then lnk.title = mdoc.short_comment @@ -388,7 +388,7 @@ redef class MClassPage end var def = select_mpropdef(mprop) var anc = def.html_link_to_anchor - anc.href = "#article:{def.nitdoc_id}.definition" + anc.href = "#{def.nitdoc_id}.definition" var lnk = new Template lnk.add new DocHTMLLabel.with_classes(classes) lnk.add anc @@ -471,7 +471,7 @@ redef class MEntitySection title.add mentity.html_signature html_title = title html_subtitle = mentity.html_namespace - toc_title = mentity.html_name + html_toc_title = mentity.html_name end super end @@ -484,16 +484,16 @@ redef class ConcernSection var mentity = self.mentity if page isa MGroupPage then html_title = null - toc_title = mentity.html_name + html_toc_title = mentity.html_name is_toc_hidden = false else if page.mentity isa MModule and mentity isa MModule then var title = new Template if mentity == page.mentity then title.add "in " - toc_title = "in {mentity.html_name}" + html_toc_title = "in {mentity.html_name}" else title.add "from " - toc_title = "from {mentity.html_name}" + html_toc_title = "from {mentity.html_name}" end title.add mentity.html_namespace html_title = title @@ -503,7 +503,7 @@ redef class ConcernSection title.add "in " title.add mentity.html_namespace html_title = title - toc_title = "in {mentity.html_name}" + html_toc_title = "in {mentity.html_name}" end super end @@ -532,7 +532,7 @@ redef class DefinitionArticle title.add mentity.html_icon title.add mentity.html_namespace html_title = title - toc_title = mentity.html_name + html_toc_title = mentity.html_name if mentity isa MModule then html_source_link = v.html_source_link(mentity.location) end @@ -542,7 +542,7 @@ redef class DefinitionArticle title.add mentity.mmodule.html_namespace html_title = mentity.html_declaration html_subtitle = title - toc_title = "in {mentity.html_name}" + html_toc_title = "in {mentity.html_name}" html_source_link = v.html_source_link(mentity.location) if page isa MEntityPage and mentity.is_intro and mentity.mmodule != page.mentity then is_short_comment = true @@ -555,13 +555,13 @@ redef class DefinitionArticle title.add mentity.html_declaration html_title = title html_subtitle = mentity.html_namespace - toc_title = mentity.html_name + html_toc_title = mentity.html_name else var title = new Template title.add "in " title.add mentity.mclassdef.html_link html_title = title - toc_title = "in {mentity.mclassdef.html_name}" + html_toc_title = "in {mentity.mclassdef.html_name}" end html_source_link = v.html_source_link(mentity.location) end @@ -576,7 +576,7 @@ redef class HomeArticle redef fun init_html_render(v, doc, page) do if v.ctx.opt_custom_title.value != null then self.html_title = v.ctx.opt_custom_title.value.to_s - self.toc_title = v.ctx.opt_custom_title.value.to_s + self.html_toc_title = v.ctx.opt_custom_title.value.to_s end self.content = v.ctx.opt_custom_intro.value super @@ -586,7 +586,7 @@ end redef class GraphArticle redef fun init_html_render(v, doc, page) do var output_dir = v.ctx.output_dir - var path = output_dir / id + var path = output_dir / graph_id var path_sh = path.escape_to_sh var file = new FileWriter.open("{path}.dot") file.write(dot) diff --git a/src/doc/doc_phases/doc_indexing.nit b/src/doc/doc_phases/doc_indexing.nit index 72df73c..1e74138 100644 --- a/src/doc/doc_phases/doc_indexing.nit +++ b/src/doc/doc_phases/doc_indexing.nit @@ -43,7 +43,7 @@ class IndexingPhase if not doc.mpropdefs.has(mpropdef) then continue var full_name = mpropdef.mclassdef.mclass.full_name var cls_url = mpropdef.mclassdef.mclass.nitdoc_url - var def_url = "{cls_url}#article:{mpropdef.nitdoc_id}.definition" + var def_url = "{cls_url}#{mpropdef.nitdoc_id}.definition" add_result_for(mproperty.name, full_name, def_url) end end diff --git a/src/doc/doc_phases/doc_intros_redefs.nit b/src/doc/doc_phases/doc_intros_redefs.nit index 5ed6f78..ae341f9 100644 --- a/src/doc/doc_phases/doc_intros_redefs.nit +++ b/src/doc/doc_phases/doc_intros_redefs.nit @@ -54,52 +54,33 @@ redef class DefinitionArticle # TODO this should move to MEntity? private fun build_mmodule_list(v: IntroRedefListPhase, doc: DocModel, mmodule: MModule) do - var section = new IntrosRedefsSection(mentity) - var group = new PanelGroup("List") + var section = new TabbedGroup("{mentity.nitdoc_id}.intros_redefs") + section.toc_title = "Intros / Redefs" + var group = new PanelGroup("list.group", "List") var intros = mmodule.intro_mclassdefs(v.ctx.min_visibility).to_a doc.mainmodule.linearize_mclassdefs(intros) - group.add_child new IntrosRedefsListArticle(mentity, "Introduces", intros) + group.add_child new MEntitiesListArticle("{mentity.nitdoc_id}.intros", "Introduces", intros) var redefs = mmodule.redef_mclassdefs(v.ctx.min_visibility).to_a doc.mainmodule.linearize_mclassdefs(redefs) - group.add_child new IntrosRedefsListArticle(mentity, "Redefines", redefs) + group.add_child new MEntitiesListArticle("{mentity.nitdoc_id}.redefs", "Redefines", redefs) section.add_child group add_child(section) end # TODO this should move to MEntity? private fun build_mclassdef_list(v: IntroRedefListPhase, doc: DocModel, mclassdef: MClassDef) do - var section = new IntrosRedefsSection(mentity) - var group = new PanelGroup("List") + var section = new TabbedGroup("{mentity.nitdoc_id}.intros_redefs") + section.toc_title = "Intros / Redefs" + var group = new PanelGroup("list.group", "List") var intros = mclassdef.collect_intro_mpropdefs(v.ctx.min_visibility).to_a # FIXME avoid diff changes # v.ctx.mainmodule.linearize_mpropdefs(intros) - group.add_child new IntrosRedefsListArticle(mentity, "Introduces", intros) + group.add_child new MEntitiesListArticle("{mentity.nitdoc_id}.intros", "Introduces", intros) var redefs = mclassdef.collect_redef_mpropdefs(v.ctx.min_visibility).to_a # FIXME avoid diff changes # v.ctx.mainmodule.linearize_mpropdefs(redefs) - group.add_child new IntrosRedefsListArticle(mentity, "Redefines", redefs) + group.add_child new MEntitiesListArticle("{mentity.nitdoc_id}.redefs", "Redefines", redefs) section.add_child group add_child(section) end - -end - -# Section that contains the intros and redefs lists. -class IntrosRedefsSection - super TabbedGroup - super MEntitySection -end - -# An article that displays a list of introduced / refined mentities. -# -# FIXME diff hack -# This can merged with InheritanceListArticle in a more generic class. -class IntrosRedefsListArticle - super MEntityArticle - - # Title displayed as header of the list. - var list_title: String - - # Intro mentities to list. - var mentities: Array[MEntity] end diff --git a/src/doc/doc_phases/doc_lin.nit b/src/doc/doc_phases/doc_lin.nit index c36756c..7864b27 100644 --- a/src/doc/doc_phases/doc_lin.nit +++ b/src/doc/doc_phases/doc_lin.nit @@ -73,7 +73,7 @@ redef class DefinitionArticle var lin = all_defs.to_a doc.mainmodule.linearize_mpropdefs(lin) if lin.length > 1 then - add_child new DefinitionLinArticle(mentity, lin) + add_child new DefinitionLinArticle("{mentity.nitdoc_id}.lin", "Linearization", lin) end end @@ -93,8 +93,11 @@ end # Display a linearized list of definitions. class DefinitionLinArticle - super MEntityArticle + super DocArticle # The linearized list to display. var mentities: Array[MEntity] + + redef fun is_hidden do return mentities.is_empty + redef var is_toc_hidden = true end diff --git a/src/doc/doc_phases/doc_poset.nit b/src/doc/doc_phases/doc_poset.nit index 0c610d4..556733e 100644 --- a/src/doc/doc_phases/doc_poset.nit +++ b/src/doc/doc_phases/doc_poset.nit @@ -46,7 +46,7 @@ redef class MModulePage # Imported modules that should appear in the documentation. var imports = new HashSet[MModule] - # Clients modules that shjould appear in the documentation. + # Clients modules that should appear in the documentation. var clients = new HashSet[MModule] redef fun build_poset(v, doc) do diff --git a/src/doc/doc_phases/doc_structure.nit b/src/doc/doc_phases/doc_structure.nit index 7491e4b..f9824d3 100644 --- a/src/doc/doc_phases/doc_structure.nit +++ b/src/doc/doc_phases/doc_structure.nit @@ -47,15 +47,15 @@ end redef class OverviewPage redef fun apply_structure(v, doc) do - var article = new HomeArticle + var article = new HomeArticle("home.article", "Home") root.add_child article # Projects list var mprojects = doc.model.mprojects.to_a var sorter = new MConcernRankSorter sorter.sort mprojects - var section = new ProjectsSection + var section = new DocSection("projects.section", "Projects") for mproject in mprojects do - section.add_child new DefinitionArticle(mproject) + section.add_child new DefinitionArticle("{mproject.nitdoc_id}.definition", mproject) end article.add_child section end @@ -69,18 +69,18 @@ redef class SearchPage v.name_sorter.sort(mclasses) var mprops = doc.mproperties.to_a v.name_sorter.sort(mprops) - root.add_child new IndexArticle(mmodules, mclasses, mprops) + root.add_child new IndexArticle("index.article", mmodules, mclasses, mprops) end end redef class MGroupPage redef fun apply_structure(v, doc) do - var section = new MEntitySection(mentity) + var section = new MEntitySection("{mentity.nitdoc_name}.section", mentity) root.add_child section if mentity.is_root then - section.add_child new IntroArticle(mentity.mproject) + section.add_child new IntroArticle("{mentity.mproject.nitdoc_id}.intro", mentity.mproject) else - section.add_child new IntroArticle(mentity) + section.add_child new IntroArticle("{mentity.nitdoc_id}.intro", mentity) end var concerns = self.concerns if concerns == null or concerns.is_empty then return @@ -90,11 +90,11 @@ redef class MGroupPage concerns.sort_with(v.concerns_sorter) mentity.mproject.booster_rank = 0 mentity.booster_rank = 0 - section.add_child new ConcernsArticle(mentity, concerns) + section.add_child new ConcernsArticle("{mentity.nitdoc_id}.concerns", mentity, concerns) for mentity in concerns do - var ssection = new ConcernSection(mentity) + var ssection = new ConcernSection("{mentity.nitdoc_id}.concern", mentity) if mentity isa MModule then - ssection.add_child new DefinitionArticle(mentity) + ssection.add_child new DefinitionArticle("{mentity.nitdoc_id}.definition", mentity) end section.add_child ssection end @@ -103,9 +103,9 @@ end redef class MModulePage redef fun apply_structure(v, doc) do - var section = new MEntitySection(mentity) + var section = new MEntitySection("{mentity.nitdoc_name}.section", mentity) root.add_child section - section.add_child new IntroArticle(mentity) + section.add_child new IntroArticle("{mentity.nitdoc_id}.intro", mentity) var concerns = self.concerns if concerns == null or concerns.is_empty then return # FIXME avoid diff @@ -116,22 +116,25 @@ redef class MModulePage mentity.mgroup.mproject.booster_rank = 0 mentity.mgroup.booster_rank = 0 mentity.booster_rank = 0 - section.add_child new ConcernsArticle(mentity, concerns) + section.add_child new ConcernsArticle("{mentity.nitdoc_id}.concerns", mentity, concerns) # reference list for mentity in concerns do - var ssection = new ConcernSection(mentity) + var ssection = new ConcernSection("{mentity.nitdoc_id}.concern", mentity) if mentity isa MModule then var mclasses = mclasses_for_mmodule(mentity).to_a v.name_sorter.sort(mclasses) for mclass in mclasses do - var article = new DefinitionListArticle(mclass) + var article = new DefinitionListArticle( + "{mclass.intro.nitdoc_id}.definition-list", mclass) var mclassdefs = mclassdefs_for(mclass).to_a if not mclassdefs.has(mclass.intro) then - article.add_child(new DefinitionArticle(mclass.intro)) + article.add_child(new DefinitionArticle( + "{mclass.intro.nitdoc_id}.definition", mclass.intro)) end doc.mainmodule.linearize_mclassdefs(mclassdefs) for mclassdef in mclassdefs do - article.add_child(new DefinitionArticle(mclassdef)) + article.add_child(new DefinitionArticle( + "{mclassdef.nitdoc_id}.definition", mclassdef)) end ssection.add_child article end @@ -165,9 +168,9 @@ end redef class MClassPage redef fun apply_structure(v, doc) do - var section = new MEntitySection(mentity) + var section = new MEntitySection("{mentity.nitdoc_name}.section", mentity) root.add_child section - section.add_child new IntroArticle(mentity) + section.add_child new IntroArticle("{mentity.nitdoc_id}.intro", mentity) var concerns = self.concerns if concerns == null or concerns.is_empty then return # FIXME diff hack @@ -178,15 +181,15 @@ redef class MClassPage mentity.intro_mmodule.mgroup.mproject.booster_rank = 0 mentity.intro_mmodule.mgroup.booster_rank = 0 mentity.intro_mmodule.booster_rank = 0 - var constructors = new ConstructorsSection(mentity) + var constructors = new DocSection("{mentity.nitdoc_id}.constructors", "Constructors") var minit = mentity.root_init if minit != null then - constructors.add_child new DefinitionArticle(minit) + constructors.add_child new DefinitionArticle("{minit.nitdoc_id}.definition", minit) end section.add_child constructors - section.add_child new ConcernsArticle(mentity, concerns) + section.add_child new ConcernsArticle("{mentity.nitdoc_id}.concerns", mentity, concerns) for mentity in concerns do - var ssection = new ConcernSection(mentity) + var ssection = new ConcernSection("{mentity.nitdoc_id}.concern", mentity) if mentity isa MModule then var mprops = mproperties_for(mentity) var by_kind = new PropertiesByKind.with_elements(mprops) @@ -196,9 +199,11 @@ redef class MClassPage for mpropdef in mpropdefs_for(mprop, mentity) do if mpropdef isa MMethodDef and mpropdef.mproperty.is_init then if mpropdef == minit then continue - constructors.add_child new DefinitionArticle(mpropdef) + constructors.add_child new DefinitionArticle( + "{mpropdef.nitdoc_id}.definition", mpropdef) else - ssection.add_child new DefinitionArticle(mpropdef) + ssection.add_child new DefinitionArticle( + "{mpropdef.nitdoc_id}.definition", mpropdef) end end end @@ -238,9 +243,9 @@ end redef class MPropertyPage redef fun apply_structure(v, doc) do - var section = new MEntitySection(mentity) + var section = new MEntitySection("{mentity.nitdoc_name}.section", mentity) root.add_child section - section.add_child new IntroArticle(mentity) + section.add_child new IntroArticle("{mentity.nitdoc_id}.intro", mentity) var concerns = self.concerns if concerns == null or concerns.is_empty then return # FIXME diff hack @@ -251,15 +256,16 @@ redef class MPropertyPage mentity.intro.mclassdef.mmodule.mgroup.mproject.booster_rank = 0 mentity.intro.mclassdef.mmodule.mgroup.booster_rank = 0 mentity.intro.mclassdef.mmodule.booster_rank = 0 - section.add_child new ConcernsArticle(mentity, concerns) + section.add_child new ConcernsArticle("{mentity.nitdoc_id}.concerns", mentity, concerns) for mentity in concerns do - var ssection = new ConcernSection(mentity) + var ssection = new ConcernSection("{mentity.nitdoc_id}.concern", mentity) if mentity isa MModule then # Add mproperties var mpropdefs = mpropdefs_for(mentity).to_a v.name_sorter.sort(mpropdefs) for mpropdef in mpropdefs do - ssection.add_child new DefinitionArticle(mpropdef) + ssection.add_child new DefinitionArticle( + "{mpropdef.nitdoc_id}.definition", mpropdef) end end section.add_child ssection @@ -288,30 +294,26 @@ end # A group of sections that can be displayed together in a tab panel. class PanelGroup super DocSection - - # The title of this group. - var group_title: String end # A DocComposite element about a MEntity. class MEntityComposite super DocComposite + redef fun title do return mentity.nitdoc_name + # MEntity documented by this page element. var mentity: MEntity end -# A list of constructors. -class ConstructorsSection - super MEntitySection -end - # A Section about a Concern. # # Those sections are used to build the page summary. class ConcernSection super MEntityComposite super DocSection + + redef fun is_toc_hidden do return is_hidden end # An article about a Mentity. @@ -322,6 +324,17 @@ abstract class MEntityArticle super DocArticle end +# An article that displays a list of mentities. +class MEntitiesListArticle + super DocArticle + + # MEntities to display. + var mentities: Array[MEntity] + + redef fun is_hidden do return mentities.is_empty +end + + # A section about a Mentity. # # Used to regroup content about a MEntity. @@ -336,6 +349,9 @@ end class IntroArticle super MEntityComposite super DocArticle + + redef var is_hidden = false + redef var is_toc_hidden = true end # An article that display a ConcernsTreee as a list. @@ -344,9 +360,11 @@ class ConcernsArticle # Concerns to list in this article. var concerns: ConcernsTree + + redef fun is_hidden do return concerns.is_empty end -# An article that displaus a list of definition belonging to a MEntity. +# An article that displays a list of definition belonging to a MEntity. class DefinitionListArticle super TabbedGroup super MEntityArticle @@ -355,6 +373,8 @@ end # An article that display the definition text of a MEntity. class DefinitionArticle super MEntityArticle + + redef var is_hidden = false end # The main project article. @@ -362,11 +382,6 @@ class HomeArticle super DocArticle end -# The project list. -class ProjectsSection - super DocArticle -end - # An article that display an index of mmodules, mclasses and mproperties. class IndexArticle super DocArticle @@ -379,4 +394,8 @@ class IndexArticle # List of mproperties to display. var mprops: Array[MProperty] + + redef fun is_hidden do + return mmodules.is_empty and mclasses.is_empty and mprops.is_empty + end end diff --git a/src/doc/html_templates/html_model.nit b/src/doc/html_templates/html_model.nit index bc8ccbe..46953d9 100644 --- a/src/doc/html_templates/html_model.nit +++ b/src/doc/html_templates/html_model.nit @@ -686,7 +686,7 @@ redef class MConcern private fun html_concern_item: ListItem do var lnk = html_link var tpl = new Template - tpl.add new Link.with_title("#concern:{nitdoc_id}", lnk.text, lnk.title) + tpl.add new Link.with_title("#{nitdoc_id}.concern", lnk.text, lnk.title) var comment = html_short_comment if comment != null then tpl.add ": " diff --git a/src/doc/html_templates/html_templates.nit b/src/doc/html_templates/html_templates.nit index ed680f0..8849fb3 100644 --- a/src/doc/html_templates/html_templates.nit +++ b/src/doc/html_templates/html_templates.nit @@ -247,12 +247,12 @@ redef class DocComposite super Template # HTML anchor id - var html_id: String is noinit, writable + var html_id: String is writable, lazy do return id # Title to display if any. # # This title can be decorated with HTML. - var html_title: nullable Writable is noinit, writable + var html_title: nullable Writable is writable, lazy do return title # Subtitle to display if any. var html_subtitle: nullable Writable is noinit, writable @@ -286,26 +286,20 @@ redef class DocComposite # Level for HTML heading. private fun hlvl: Int do return depth - # Is `self` not displayed in the page. - # - # By default, empty elements are hidden. - fun is_hidden: Bool do return is_empty - # A short, undecorated title that goes in the table of contents. # # By default, returns `html_title.to_s`, subclasses should redefine it. - var toc_title: String is lazy, writable do return html_title.to_s - - # Is `self` hidden in the table of content? - var is_toc_hidden = false is writable + var html_toc_title: nullable String is lazy, writable do + if html_title == null then return toc_title + return html_title.write_to_string + end # Render this element in a table of contents. private fun render_toc_item(lst: UnorderedList) do - if is_toc_hidden then return + if is_toc_hidden or html_toc_title == null then return var content = new Template - content.add new Link("#{html_id}", toc_title) - + content.add new Link("#{html_id}", html_toc_title.to_s) if not children.is_empty then var sublst = new UnorderedList sublst.css_classes.add "nav" @@ -327,6 +321,12 @@ redef class DocComposite end end +redef class DocRoot + redef fun rendering do + for child in children do addn child.write_to_string + end +end + redef class DocSection super BSComponent @@ -359,21 +359,20 @@ redef class TabbedGroup var tabs = new DocTabs("{html_id}.tabs", "") for child in children do if child.is_hidden then continue - tabs.add_panel new DocTabPanel(child.html_tab_id, child.toc_title, child) + var title = child.html_toc_title or else child.toc_title or else "" + tabs.add_panel new DocTabPanel(child.html_tab_id, title, child) end addn tabs end end redef class PanelGroup - redef var html_id is lazy do return "group:{group_title.to_lower.to_snake_case}" redef var html_title = null - redef var toc_title is lazy do return group_title + redef var toc_title is lazy do return title or else "" redef var is_toc_hidden = true end redef class HomeArticle - redef var html_id = "article:home" redef var html_title = "Overview" # HTML content to display on the home page. @@ -389,11 +388,7 @@ redef class HomeArticle end redef class IndexArticle - redef var html_id = "article:index" redef var html_title = "Index" - redef fun is_empty do - return mmodules.is_empty and mclasses.is_empty and mprops.is_empty - end redef fun render_body do addn "
" @@ -428,50 +423,21 @@ redef class IndexArticle end end -redef class ProjectsSection - redef var html_id = "section:projects" - redef var html_title = "Projects" -end - redef class MEntityComposite - redef var html_id is lazy do return mentity.nitdoc_id redef var html_title is lazy do return mentity.nitdoc_name end redef class MEntitySection - redef var html_id is lazy do return "section:{mentity.nitdoc_name}" redef var html_title is lazy do return mentity.html_name redef var html_subtitle is lazy do return mentity.html_declaration end -redef class ConstructorsSection - redef var html_id is lazy do return "article:{mentity.nitdoc_id}.constructors" - redef var html_title = "Constructors" - redef var html_subtitle = null - redef fun is_toc_hidden do return is_empty -end - redef class ConcernSection - redef var html_id is lazy do return "concern:{mentity.nitdoc_id}" redef var html_title is lazy do return "in {mentity.nitdoc_name}" - redef fun is_toc_hidden do return is_empty -end - -redef class ImportationListSection - redef var html_id is lazy do return "section:{mentity.nitdoc_id}.importation" - redef var html_title is lazy do return "Dependencies" -end - -redef class InheritanceListSection - redef var html_id is lazy do return "section:{mentity.nitdoc_id}.inheritance" - redef var html_title is lazy do return "Inheritance" end redef class IntroArticle - redef var html_id is lazy do return "article:{mentity.nitdoc_id}.intro" redef var html_title = null - redef var is_hidden = false - redef var is_toc_hidden = true # Link to source to display if any. var html_source_link: nullable Writable is noinit, writable @@ -484,7 +450,8 @@ redef class IntroArticle end for child in children do if child.is_hidden then continue - tabs.add_panel new DocTabPanel(child.html_tab_id, child.toc_title, child) + var title = child.html_toc_title or else child.toc_title or else "" + tabs.add_panel new DocTabPanel(child.html_tab_id, title, child) end var lnk = html_source_link if lnk != null then @@ -495,15 +462,11 @@ redef class IntroArticle end redef class ConcernsArticle - redef var html_id is lazy do return "article:{mentity.nitdoc_id}.concerns" redef var html_title = "Concerns" - redef fun is_hidden do return concerns.is_empty redef fun render_body do add concerns.html_list end redef class DefinitionListArticle - redef var html_id is lazy do return "article:{mentity.nitdoc_id}.definition-list" - redef var html_title is lazy do var title = new Template title.add mentity.html_icon @@ -512,14 +475,12 @@ redef class DefinitionListArticle end redef var html_subtitle is lazy do return mentity.html_namespace - redef var toc_title is lazy do return mentity.html_name + redef var html_toc_title is lazy do return mentity.html_name end redef class DefinitionArticle - redef var html_id is lazy do return "article:{mentity.nitdoc_id}.definition" redef var html_title is lazy do return mentity.html_name redef var html_subtitle is lazy do return mentity.html_declaration - redef var is_hidden = false # Does `self` display only it's title and no body? # @@ -549,7 +510,8 @@ redef class DefinitionArticle end for child in children do if child.is_hidden then continue - tabs.add_panel new DocTabPanel(child.html_tab_id, child.toc_title, child) + var title = child.html_toc_title or else child.toc_title or else "" + tabs.add_panel new DocTabPanel(child.html_tab_id, title, child) end var lnk = html_source_link if lnk != null then @@ -559,52 +521,18 @@ redef class DefinitionArticle end end -redef class HierarchyListArticle - redef var html_id is lazy do return "article:{list_title}_{mentity.nitdoc_id}.hierarchy" - redef var html_title is lazy do return list_title - redef fun is_empty do return mentities.is_empty - redef var is_toc_hidden = true - +redef class MEntitiesListArticle redef fun render_body do var lst = new UnorderedList lst.css_classes.add "list-unstyled list-definition" for mentity in mentities do lst.add_li mentity.html_list_item end - addn lst - end -end - -redef class IntrosRedefsSection - redef var html_id is lazy do return "article:{mentity.nitdoc_id}.intros_redefs" - redef var toc_title do return "Intros / Redefs" - redef var html_title = null - redef var html_subtitle = null - redef var is_toc_hidden = true -end - -redef class IntrosRedefsListArticle - redef var html_id is lazy do return "article:{list_title}_{mentity.nitdoc_id}.intros_redefs" - redef var html_title is lazy do return list_title - redef fun is_hidden do return mentities.is_empty - redef var is_toc_hidden = true - - redef fun render_body do - var lst = new UnorderedList - lst.css_classes.add "list-unstyled list-labeled" - for mentity in mentities do - lst.add_li mentity.html_list_item - end add lst end end redef class DefinitionLinArticle - redef var html_id is lazy do return "article:{mentity.nitdoc_id}.lin" - redef var html_title is lazy do return "Linearization" - redef fun is_hidden do return mentities.is_empty - redef var is_toc_hidden = true - redef fun render_body do var lst = new UnorderedList lst.css_classes.add "list-unstyled list-labeled" @@ -626,11 +554,7 @@ redef class DefinitionLinArticle end redef class GraphArticle - redef var html_id is lazy do return "article:{mentity.nitdoc_id}.graph" redef var html_title = null - redef var toc_title do return "Graph" - redef var is_hidden = false - redef var is_toc_hidden = true # HTML map used to display link. # @@ -639,8 +563,8 @@ redef class GraphArticle redef fun render_body do addn "
" - addn " {graph_title}" + addn " {title or else ""}" add map addn "
" end diff --git a/src/frontend/serialization_phase.nit b/src/frontend/serialization_phase.nit index 90924f2..8d576ba 100644 --- a/src/frontend/serialization_phase.nit +++ b/src/frontend/serialization_phase.nit @@ -34,27 +34,118 @@ redef class ToolContext private fun place_holder_type_name: String do return "PlaceHolderTypeWhichShouldNotExist" end +redef class ANode + # Is this node annotated to be made serializable? + private fun is_serialize: Bool do return false + + # Is this node annotated to not be made serializable? + private fun is_noserialize: Bool do return false + + private fun accept_precise_type_visitor(v: PreciseTypeVisitor) do visit_all(v) +end + +redef class ADefinition + + redef fun is_serialize do + return get_annotations("serialize").not_empty or + get_annotations("auto_serializable").not_empty + end + + redef fun is_noserialize do + return get_annotations("noserialize").not_empty + end +end + # TODO add annotations on attributes (volatile, sensitive or do_not_serialize?) private class SerializationPhasePreModel super Phase - redef fun process_annotated_node(nclassdef, nat) + redef fun process_annotated_node(node, nat) do # Skip if we are not interested - if nat.n_atid.n_id.text != "auto_serializable" then return - if not nclassdef isa AStdClassdef then - toolcontext.error(nclassdef.location, "Syntax Error: only a concrete class can be automatically serialized.") + var text = nat.n_atid.n_id.text + var serialize = text == "auto_serializable" or text == "serialize" + var noserialize = text == "noserialize" + if not (serialize or noserialize) then return + + # Check legality of annotation + if node isa AModuledecl then + if noserialize then toolcontext.error(node.location, "Syntax Error: superfluous use of `{text}`, by default a module is `{text}`") + return + else if not (node isa AStdClassdef or node isa AAttrPropdef) then + toolcontext.error(node.location, + "Syntax Error: only a class, a module or an attribute can be annotated with `{text}`.") return + else if serialize and node.is_noserialize then + toolcontext.error(node.location, + "Syntax Error: an entity cannot be both `{text}` and `noserialize`.") + return + else if node.as(Prod).get_annotations(text).length > 1 then + toolcontext.warning(node.location, "useless-{text}", + "Warning: duplicated annotation `{text}`.") end - # Add `super Serializable` - var sc = toolcontext.parse_superclass("Serializable") - sc.location = nat.location - nclassdef.n_propdefs.add sc + # Check the `serialize` state of the parent + if not node isa AModuledecl then + var up_serialize = false + var up: nullable ANode = node + loop + up = up.parent + if up == null then + break + else if up.is_serialize then + up_serialize = true + break + else if up.is_noserialize then + break + end + end - generate_serialization_method(nclassdef) + # Check for useless double declarations + if serialize and up_serialize then + toolcontext.warning(node.location, "useless-serialize", + "Warning: superfluous use of `{text}`.") + else if noserialize and not up_serialize then + toolcontext.warning(node.location, "useless-noserialize", + "Warning: superfluous use of `{text}`.") + end + end + end - generate_deserialization_init(nclassdef) + redef fun process_nclassdef(nclassdef) + do + if not nclassdef isa AStdClassdef then return + + # Is there a declaration on the classdef or the module? + var serialize = nclassdef.is_serialize + + if not serialize and not nclassdef.is_noserialize then + # Is the module marked serialize? + serialize = nclassdef.parent.as(AModule).is_serialize + end + + var per_attribute = false + if not serialize then + # Is there an attribute marked serialize? + for npropdef in nclassdef.n_propdefs do + if npropdef.is_serialize then + serialize = true + per_attribute = true + break + end + end + end + + if serialize then + # Add `super Serializable` + var sc = toolcontext.parse_superclass("Serializable") + sc.location = nclassdef.location + nclassdef.n_propdefs.add sc + + # Add services + generate_serialization_method(nclassdef, per_attribute) + generate_deserialization_init(nclassdef, per_attribute) + end end redef fun process_nmodule(nmodule) @@ -65,8 +156,7 @@ private class SerializationPhasePreModel # collect all classes var auto_serializable_nclassdefs = new Array[AStdClassdef] for nclassdef in nmodule.n_classdefs do - if nclassdef isa AStdClassdef and - not nclassdef.get_annotations("auto_serializable").is_empty then + if nclassdef isa AStdClassdef and nclassdef.is_serialize then auto_serializable_nclassdefs.add nclassdef end end @@ -76,7 +166,7 @@ private class SerializationPhasePreModel end end - fun generate_serialization_method(nclassdef: AClassdef) + fun generate_serialization_method(nclassdef: AClassdef, per_attribute: Bool) do var npropdefs = nclassdef.n_propdefs @@ -86,6 +176,11 @@ private class SerializationPhasePreModel code.add " super" for attribute in npropdefs do if attribute isa AAttrPropdef then + + # Is `attribute` to be skipped? + if (per_attribute and not attribute.is_serialize) or + attribute.is_noserialize then continue + var name = attribute.name code.add " v.serialize_attribute(\"{name}\", {name})" end @@ -97,7 +192,7 @@ private class SerializationPhasePreModel end # Add a constructor to the automated nclassdef - fun generate_deserialization_init(nclassdef: AStdClassdef) + fun generate_deserialization_init(nclassdef: AClassdef, per_attribute: Bool) do var npropdefs = nclassdef.n_propdefs @@ -108,6 +203,11 @@ private class SerializationPhasePreModel code.add " v.notify_of_creation self" for attribute in npropdefs do if attribute isa AAttrPropdef then + + # Is `attribute` to be skipped? + if (per_attribute and not attribute.is_serialize) or + attribute.is_noserialize then continue + var n_type = attribute.n_type var type_name if n_type == null then @@ -201,10 +301,6 @@ private class PreciseTypeVisitor redef fun visit(n) do n.accept_precise_type_visitor(self) end -redef class ANode - private fun accept_precise_type_visitor(v: PreciseTypeVisitor) do visit_all(v) -end - redef class AIsaExpr redef fun accept_precise_type_visitor(v) do @@ -257,6 +353,8 @@ redef class AModule end private var inits_to_retype = new Array[AMethPropdef] + + redef fun is_serialize do return n_moduledecl != null and n_moduledecl.is_serialize end redef class AStdClassdef diff --git a/src/nitserial.nit b/src/nitserial.nit index 0b60a1b..8ead776 100644 --- a/src/nitserial.nit +++ b/src/nitserial.nit @@ -94,7 +94,7 @@ end redef class MClassType redef fun is_visible_from(mmodule) do - return mmodule.is_visible(mclass.intro_mmodule, public_visibility) + return mmodule.is_visible(mclass.intro_mmodule, mclass.visibility) end end diff --git a/tests/sav/nitg-e/test_json_deserialization_alt1.res b/tests/sav/nitg-e/test_json_deserialization_alt1.res index 90e0d60..f4b4a49 100644 --- a/tests/sav/nitg-e/test_json_deserialization_alt1.res +++ b/tests/sav/nitg-e/test_json_deserialization_alt1.res @@ -1,40 +1,40 @@ -Runtime error: Aborted (../lib/serialization/serialization.nit:109) +Runtime error: Aborted (../lib/serialization/serialization.nit:111) # Nit: - + # Json: {"__kind": "obj", "__id": 0, "__class": "A", "b": true, "c": {"__kind": "char", "__val": "a"}, "f": 0.123, "i": 1234, "s": "asdf", "n": null} # Back in Nit: - + # Nit: - 1111 qwer> + 1111 qwer> # Json: {"__kind": "obj", "__id": 0, "__class": "B", "b": false, "c": {"__kind": "char", "__val": "b"}, "f": 123.123, "i": 2345, "s": "hjkl", "n": null, "ii": 1111, "ss": "qwer"} # Back in Nit: - 1111 qwer> + 1111 qwer> # Nit: - 1111 qwer>> + 1111 qwer>> # Json: {"__kind": "obj", "__id": 0, "__class": "C", "a": {"__kind": "obj", "__id": 1, "__class": "A", "b": true, "c": {"__kind": "char", "__val": "a"}, "f": 0.123, "i": 1234, "s": "asdf", "n": null}, "b": {"__kind": "obj", "__id": 2, "__class": "B", "b": false, "c": {"__kind": "char", "__val": "b"}, "f": 123.123, "i": 2345, "s": "hjkl", "n": null, "ii": 1111, "ss": "qwer"}, "aa": {"__kind": "ref", "__id": 1}} # Back in Nit: - 1111 qwer>> + 1111 qwer>> # Nit: -<- false> 1111 f" \/> true> +<- false p4ssw0rd> 1111 f" \/> true> # Json: {"__kind": "obj", "__id": 0, "__class": "D", "b": false, "c": {"__kind": "char", "__val": "b"}, "f": 123.123, "i": 2345, "s": "new line ->\n<-", "n": null, "ii": 1111, "ss": "\tf\"\r\\\/", "d": {"__kind": "ref", "__id": 0}} # Back in Nit: -<- false> 1111 f" \/> true> +<- false p4ssw0rd> 1111 f" \/> true> Error: doesn't know how to deserialize class "Array" diff --git a/tests/sav/nitg-e/test_serialization_alt2.res b/tests/sav/nitg-e/test_serialization_alt2.res new file mode 100644 index 0000000..34da2d6 --- /dev/null +++ b/tests/sav/nitg-e/test_serialization_alt2.res @@ -0,0 +1,28 @@ +alt/test_serialization_alt2.nit:22,1--47,3: Warning: superfluous use of `serialize`. +alt/test_serialization_alt2.nit:70,1--86,3: Warning: superfluous use of `auto_serializable`. +alt/test_serialization_alt2.nit:88,1--96,3: Warning: superfluous use of `auto_serializable`. +# Nit: + + +# Json: +{"__kind": "obj", "__id": 0, "__class": "A", "b": true, "f": 0.123, "i": 1234, "s": "asdf", "n": null, "array": {"__kind": "obj", "__id": 1, "__class": "Array", "__length": 3, "__items": [88, "hello", null]}} + +# Nit: + 1111 qwer> + +# Json: +{"__kind": "obj", "__id": 0, "__class": "B", "b": false, "f": 123.123, "i": 2345, "s": "hjkl", "n": null, "array": {"__kind": "obj", "__id": 1, "__class": "Array", "__length": 3, "__items": [88, "hello", null]}} + +# Nit: + 1111 qwer>> + +# Json: +{"__kind": "obj", "__id": 0, "__class": "C", "a": {"__kind": "obj", "__id": 1, "__class": "A", "b": true, "f": 0.123, "i": 1234, "s": "asdf", "n": null, "array": {"__kind": "obj", "__id": 2, "__class": "Array", "__length": 3, "__items": [88, "hello", null]}}, "b": {"__kind": "obj", "__id": 3, "__class": "B", "b": false, "f": 123.123, "i": 2345, "s": "hjkl", "n": null, "array": {"__kind": "obj", "__id": 4, "__class": "Array", "__length": 3, "__items": [88, "hello", null]}}, "aa": {"__kind": "ref", "__id": 1}} + +# Nit: + +<- false> 1111 f" \/> true> + +# Json: +{"__kind": "obj", "__id": 0, "__class": "D", "b": false, "f": 123.123, "i": 2345, "s": "new line ->\n<-", "n": null, "array": {"__kind": "obj", "__id": 1, "__class": "Array", "__length": 3, "__items": [88, "hello", null]}, "d": {"__kind": "ref", "__id": 0}} + diff --git a/tests/sav/nitg-e/test_serialization_alt3.res b/tests/sav/nitg-e/test_serialization_alt3.res new file mode 100644 index 0000000..afd0ee8 --- /dev/null +++ b/tests/sav/nitg-e/test_serialization_alt3.res @@ -0,0 +1,26 @@ +alt/test_serialization_alt3.nit:49,1--68,3: Warning: superfluous use of `noserialize`. +# Nit: + + +# Json: +{"__kind": "obj", "__id": 0, "__class": "A", "b": true, "c": {"__kind": "char", "__val": "a"}, "f": 0.123, "i": 1234, "s": "asdf", "n": null, "array": {"__kind": "obj", "__id": 1, "__class": "Array", "__length": 3, "__items": [88, "hello", null]}} + +# Nit: + 1111 qwer> + +# Json: +{"__kind": "obj", "__id": 0, "__class": "B", "b": false, "c": {"__kind": "char", "__val": "b"}, "f": 123.123, "i": 2345, "s": "hjkl", "n": null, "array": {"__kind": "obj", "__id": 1, "__class": "Array", "__length": 3, "__items": [88, "hello", null]}} + +# Nit: + 1111 qwer>> + +# Json: +{"__kind": "obj", "__id": 0, "__class": "C", "a": {"__kind": "obj", "__id": 1, "__class": "A", "b": true, "c": {"__kind": "char", "__val": "a"}, "f": 0.123, "i": 1234, "s": "asdf", "n": null, "array": {"__kind": "obj", "__id": 2, "__class": "Array", "__length": 3, "__items": [88, "hello", null]}}, "b": {"__kind": "obj", "__id": 3, "__class": "B", "b": false, "c": {"__kind": "char", "__val": "b"}, "f": 123.123, "i": 2345, "s": "hjkl", "n": null, "array": {"__kind": "obj", "__id": 4, "__class": "Array", "__length": 3, "__items": [88, "hello", null]}}, "aa": {"__kind": "ref", "__id": 1}} + +# Nit: + +<- false> 1111 f" \/> true> + +# Json: +{"__kind": "obj", "__id": 0, "__class": "D", "b": false, "c": {"__kind": "char", "__val": "b"}, "f": 123.123, "i": 2345, "s": "new line ->\n<-", "n": null, "array": {"__kind": "obj", "__id": 1, "__class": "Array", "__length": 3, "__items": [88, "hello", null]}, "d": {"__kind": "ref", "__id": 0}} + diff --git a/tests/sav/nitg-e/test_serialization_alt4.res b/tests/sav/nitg-e/test_serialization_alt4.res new file mode 100644 index 0000000..e843c62 --- /dev/null +++ b/tests/sav/nitg-e/test_serialization_alt4.res @@ -0,0 +1,26 @@ +alt/test_serialization_alt4.nit:29,2--31,26: Warning: superfluous use of `serialize`. +# Nit: + + +# Json: +{"__kind": "obj", "__id": 0, "__class": "A", "b": true, "c": {"__kind": "char", "__val": "a"}, "f": 0.123, "i": 1234, "s": "asdf", "n": null, "array": {"__kind": "obj", "__id": 1, "__class": "Array", "__length": 3, "__items": [88, "hello", null]}} + +# Nit: + 1111 qwer> + +# Json: +{"__kind": "obj", "__id": 0, "__class": "B", "b": false, "c": {"__kind": "char", "__val": "b"}, "f": 123.123, "i": 2345, "s": "hjkl", "n": null, "array": {"__kind": "obj", "__id": 1, "__class": "Array", "__length": 3, "__items": [88, "hello", null]}, "ii": 1111, "ss": "qwer"} + +# Nit: + 1111 qwer>> + +# Json: +{"__kind": "obj", "__id": 0, "__class": "C", "a": {"__kind": "obj", "__id": 1, "__class": "A", "b": true, "c": {"__kind": "char", "__val": "a"}, "f": 0.123, "i": 1234, "s": "asdf", "n": null, "array": {"__kind": "obj", "__id": 2, "__class": "Array", "__length": 3, "__items": [88, "hello", null]}}, "b": {"__kind": "obj", "__id": 3, "__class": "B", "b": false, "c": {"__kind": "char", "__val": "b"}, "f": 123.123, "i": 2345, "s": "hjkl", "n": null, "array": {"__kind": "obj", "__id": 4, "__class": "Array", "__length": 3, "__items": [88, "hello", null]}, "ii": 1111, "ss": "qwer"}, "aa": {"__kind": "ref", "__id": 1}} + +# Nit: + +<- false> 1111 f" \/> true> + +# Json: +{"__kind": "obj", "__id": 0, "__class": "D", "b": false, "c": {"__kind": "char", "__val": "b"}, "f": 123.123, "i": 2345, "s": "new line ->\n<-", "n": null, "array": {"__kind": "obj", "__id": 1, "__class": "Array", "__length": 3, "__items": [88, "hello", null]}, "ii": 1111, "ss": "\tf\"\r\\\/", "d": {"__kind": "ref", "__id": 0}} + diff --git a/tests/sav/nitg-e/test_serialization_alt5.res b/tests/sav/nitg-e/test_serialization_alt5.res new file mode 100644 index 0000000..d4ba4e1 --- /dev/null +++ b/tests/sav/nitg-e/test_serialization_alt5.res @@ -0,0 +1,26 @@ +alt/test_serialization_alt5.nit:22,1--47,3: Warning: duplicated annotation `serialize`. +# Nit: + + +# Json: +{"__kind": "obj", "__id": 0, "__class": "A", "b": true, "c": {"__kind": "char", "__val": "a"}, "f": 0.123, "i": 1234, "s": "asdf", "n": null, "array": {"__kind": "obj", "__id": 1, "__class": "Array", "__length": 3, "__items": [88, "hello", null]}} + +# Nit: + 1111 qwer> + +# Json: +{"__kind": "obj", "__id": 0, "__class": "B", "b": false, "c": {"__kind": "char", "__val": "b"}, "f": 123.123, "i": 2345, "s": "hjkl", "n": null, "array": {"__kind": "obj", "__id": 1, "__class": "Array", "__length": 3, "__items": [88, "hello", null]}, "ii": 1111, "ss": "qwer"} + +# Nit: + 1111 qwer>> + +# Json: +{"__kind": "obj", "__id": 0, "__class": "C", "a": {"__kind": "obj", "__id": 1, "__class": "A", "b": true, "c": {"__kind": "char", "__val": "a"}, "f": 0.123, "i": 1234, "s": "asdf", "n": null, "array": {"__kind": "obj", "__id": 2, "__class": "Array", "__length": 3, "__items": [88, "hello", null]}}, "b": {"__kind": "obj", "__id": 3, "__class": "B", "b": false, "c": {"__kind": "char", "__val": "b"}, "f": 123.123, "i": 2345, "s": "hjkl", "n": null, "array": {"__kind": "obj", "__id": 4, "__class": "Array", "__length": 3, "__items": [88, "hello", null]}, "ii": 1111, "ss": "qwer"}, "aa": {"__kind": "ref", "__id": 1}} + +# Nit: + +<- false> 1111 f" \/> true> + +# Json: +{"__kind": "obj", "__id": 0, "__class": "D", "b": false, "c": {"__kind": "char", "__val": "b"}, "f": 123.123, "i": 2345, "s": "new line ->\n<-", "n": null, "array": {"__kind": "obj", "__id": 1, "__class": "Array", "__length": 3, "__items": [88, "hello", null]}, "ii": 1111, "ss": "\tf\"\r\\\/", "d": {"__kind": "ref", "__id": 0}} + diff --git a/tests/sav/test_json_deserialization.res b/tests/sav/test_json_deserialization.res index 047314c..f4172ad 100644 --- a/tests/sav/test_json_deserialization.res +++ b/tests/sav/test_json_deserialization.res @@ -1,38 +1,38 @@ # Nit: - + # Json: {"__kind": "obj", "__id": 0, "__class": "A", "b": true, "c": {"__kind": "char", "__val": "a"}, "f": 0.123, "i": 1234, "s": "asdf", "n": null} # Back in Nit: - + # Nit: - 1111 qwer> + 1111 qwer> # Json: {"__kind": "obj", "__id": 0, "__class": "B", "b": false, "c": {"__kind": "char", "__val": "b"}, "f": 123.123, "i": 2345, "s": "hjkl", "n": null, "ii": 1111, "ss": "qwer"} # Back in Nit: - 1111 qwer> + 1111 qwer> # Nit: - 1111 qwer>> + 1111 qwer>> # Json: {"__kind": "obj", "__id": 0, "__class": "C", "a": {"__kind": "obj", "__id": 1, "__class": "A", "b": true, "c": {"__kind": "char", "__val": "a"}, "f": 0.123, "i": 1234, "s": "asdf", "n": null}, "b": {"__kind": "obj", "__id": 2, "__class": "B", "b": false, "c": {"__kind": "char", "__val": "b"}, "f": 123.123, "i": 2345, "s": "hjkl", "n": null, "ii": 1111, "ss": "qwer"}, "aa": {"__kind": "ref", "__id": 1}} # Back in Nit: - 1111 qwer>> + 1111 qwer>> # Nit: -<- false> 1111 f" \/> true> +<- false p4ssw0rd> 1111 f" \/> true> # Json: {"__kind": "obj", "__id": 0, "__class": "D", "b": false, "c": {"__kind": "char", "__val": "b"}, "f": 123.123, "i": 2345, "s": "new line ->\n<-", "n": null, "ii": 1111, "ss": "\tf\"\r\\\/", "d": {"__kind": "ref", "__id": 0}} # Back in Nit: -<- false> 1111 f" \/> true> +<- false p4ssw0rd> 1111 f" \/> true> diff --git a/tests/sav/test_json_deserialization_alt1.res b/tests/sav/test_json_deserialization_alt1.res index 58293c5..8c7e49a 100644 --- a/tests/sav/test_json_deserialization_alt1.res +++ b/tests/sav/test_json_deserialization_alt1.res @@ -1,40 +1,40 @@ # Nit: - + # Json: {"__kind": "obj", "__id": 0, "__class": "A", "b": true, "c": {"__kind": "char", "__val": "a"}, "f": 0.123, "i": 1234, "s": "asdf", "n": null} # Back in Nit: - + # Nit: - 1111 qwer> + 1111 qwer> # Json: {"__kind": "obj", "__id": 0, "__class": "B", "b": false, "c": {"__kind": "char", "__val": "b"}, "f": 123.123, "i": 2345, "s": "hjkl", "n": null, "ii": 1111, "ss": "qwer"} # Back in Nit: - 1111 qwer> + 1111 qwer> # Nit: - 1111 qwer>> + 1111 qwer>> # Json: {"__kind": "obj", "__id": 0, "__class": "C", "a": {"__kind": "obj", "__id": 1, "__class": "A", "b": true, "c": {"__kind": "char", "__val": "a"}, "f": 0.123, "i": 1234, "s": "asdf", "n": null}, "b": {"__kind": "obj", "__id": 2, "__class": "B", "b": false, "c": {"__kind": "char", "__val": "b"}, "f": 123.123, "i": 2345, "s": "hjkl", "n": null, "ii": 1111, "ss": "qwer"}, "aa": {"__kind": "ref", "__id": 1}} # Back in Nit: - 1111 qwer>> + 1111 qwer>> # Nit: -<- false> 1111 f" \/> true> +<- false p4ssw0rd> 1111 f" \/> true> # Json: {"__kind": "obj", "__id": 0, "__class": "D", "b": false, "c": {"__kind": "char", "__val": "b"}, "f": 123.123, "i": 2345, "s": "new line ->\n<-", "n": null, "ii": 1111, "ss": "\tf\"\r\\\/", "d": {"__kind": "ref", "__id": 0}} # Back in Nit: -<- false> 1111 f" \/> true> +<- false p4ssw0rd> 1111 f" \/> true> # Nit: diff --git a/tests/sav/test_json_deserialization_alt2.res b/tests/sav/test_json_deserialization_alt2.res index 99e49d6..2dde071 100644 --- a/tests/sav/test_json_deserialization_alt2.res +++ b/tests/sav/test_json_deserialization_alt2.res @@ -1,24 +1,24 @@ # Nit: - + # Json: {"b": true, "c": "a", "f": 0.123, "i": 1234, "s": "asdf", "n": null} # Nit: - 1111 qwer> + 1111 qwer> # Json: {"b": false, "c": "b", "f": 123.123, "i": 2345, "s": "hjkl", "n": null, "ii": 1111, "ss": "qwer"} # Nit: - 1111 qwer>> + 1111 qwer>> # Json: {"a": {"b": true, "c": "a", "f": 0.123, "i": 1234, "s": "asdf", "n": null}, "b": {"b": false, "c": "b", "f": 123.123, "i": 2345, "s": "hjkl", "n": null, "ii": 1111, "ss": "qwer"}, "aa": {"b": true, "c": "a", "f": 0.123, "i": 1234, "s": "asdf", "n": null}} # Nit: -<- false> 1111 f" \/> true> +<- false p4ssw0rd> 1111 f" \/> true> # Json: {"b": false, "c": "b", "f": 123.123, "i": 2345, "s": "new line ->\n<-", "n": null, "ii": 1111, "ss": "\tf\"\r\\\/", "d": null} diff --git a/tests/sav/test_serialization_alt2.res b/tests/sav/test_serialization_alt2.res new file mode 100644 index 0000000..e5910cf --- /dev/null +++ b/tests/sav/test_serialization_alt2.res @@ -0,0 +1,28 @@ +alt/test_serialization_alt2.nit:22,1--47,3: Warning: superfluous use of `serialize`. +alt/test_serialization_alt2.nit:70,1--86,3: Warning: superfluous use of `auto_serializable`. +alt/test_serialization_alt2.nit:88,1--96,3: Warning: superfluous use of `auto_serializable`. +# Nit: + + +# Json: +{"__kind": "obj", "__id": 0, "__class": "A", "b": true, "f": 0.123, "i": 1234, "s": "asdf", "n": null, "array": {"__kind": "obj", "__id": 1, "__class": "Array[nullable Object]", "__length": 3, "__items": [88, "hello", null]}} + +# Nit: + 1111 qwer> + +# Json: +{"__kind": "obj", "__id": 0, "__class": "B", "b": false, "f": 123.123, "i": 2345, "s": "hjkl", "n": null, "array": {"__kind": "obj", "__id": 1, "__class": "Array[nullable Object]", "__length": 3, "__items": [88, "hello", null]}} + +# Nit: + 1111 qwer>> + +# Json: +{"__kind": "obj", "__id": 0, "__class": "C", "a": {"__kind": "obj", "__id": 1, "__class": "A", "b": true, "f": 0.123, "i": 1234, "s": "asdf", "n": null, "array": {"__kind": "obj", "__id": 2, "__class": "Array[nullable Object]", "__length": 3, "__items": [88, "hello", null]}}, "b": {"__kind": "obj", "__id": 3, "__class": "B", "b": false, "f": 123.123, "i": 2345, "s": "hjkl", "n": null, "array": {"__kind": "obj", "__id": 4, "__class": "Array[nullable Object]", "__length": 3, "__items": [88, "hello", null]}}, "aa": {"__kind": "ref", "__id": 1}} + +# Nit: + +<- false> 1111 f" \/> true> + +# Json: +{"__kind": "obj", "__id": 0, "__class": "D", "b": false, "f": 123.123, "i": 2345, "s": "new line ->\n<-", "n": null, "array": {"__kind": "obj", "__id": 1, "__class": "Array[nullable Object]", "__length": 3, "__items": [88, "hello", null]}, "d": {"__kind": "ref", "__id": 0}} + diff --git a/tests/sav/test_serialization_alt3.res b/tests/sav/test_serialization_alt3.res new file mode 100644 index 0000000..c8f072c --- /dev/null +++ b/tests/sav/test_serialization_alt3.res @@ -0,0 +1,26 @@ +alt/test_serialization_alt3.nit:49,1--68,3: Warning: superfluous use of `noserialize`. +# Nit: + + +# Json: +{"__kind": "obj", "__id": 0, "__class": "A", "b": true, "c": {"__kind": "char", "__val": "a"}, "f": 0.123, "i": 1234, "s": "asdf", "n": null, "array": {"__kind": "obj", "__id": 1, "__class": "Array[nullable Object]", "__length": 3, "__items": [88, "hello", null]}} + +# Nit: + 1111 qwer> + +# Json: +{"__kind": "obj", "__id": 0, "__class": "B", "b": false, "c": {"__kind": "char", "__val": "b"}, "f": 123.123, "i": 2345, "s": "hjkl", "n": null, "array": {"__kind": "obj", "__id": 1, "__class": "Array[nullable Object]", "__length": 3, "__items": [88, "hello", null]}} + +# Nit: + 1111 qwer>> + +# Json: +{"__kind": "obj", "__id": 0, "__class": "C", "a": {"__kind": "obj", "__id": 1, "__class": "A", "b": true, "c": {"__kind": "char", "__val": "a"}, "f": 0.123, "i": 1234, "s": "asdf", "n": null, "array": {"__kind": "obj", "__id": 2, "__class": "Array[nullable Object]", "__length": 3, "__items": [88, "hello", null]}}, "b": {"__kind": "obj", "__id": 3, "__class": "B", "b": false, "c": {"__kind": "char", "__val": "b"}, "f": 123.123, "i": 2345, "s": "hjkl", "n": null, "array": {"__kind": "obj", "__id": 4, "__class": "Array[nullable Object]", "__length": 3, "__items": [88, "hello", null]}}, "aa": {"__kind": "ref", "__id": 1}} + +# Nit: + +<- false> 1111 f" \/> true> + +# Json: +{"__kind": "obj", "__id": 0, "__class": "D", "b": false, "c": {"__kind": "char", "__val": "b"}, "f": 123.123, "i": 2345, "s": "new line ->\n<-", "n": null, "array": {"__kind": "obj", "__id": 1, "__class": "Array[nullable Object]", "__length": 3, "__items": [88, "hello", null]}, "d": {"__kind": "ref", "__id": 0}} + diff --git a/tests/sav/test_serialization_alt4.res b/tests/sav/test_serialization_alt4.res new file mode 100644 index 0000000..966388f --- /dev/null +++ b/tests/sav/test_serialization_alt4.res @@ -0,0 +1,26 @@ +alt/test_serialization_alt4.nit:29,2--31,26: Warning: superfluous use of `serialize`. +# Nit: + + +# Json: +{"__kind": "obj", "__id": 0, "__class": "A", "b": true, "c": {"__kind": "char", "__val": "a"}, "f": 0.123, "i": 1234, "s": "asdf", "n": null, "array": {"__kind": "obj", "__id": 1, "__class": "Array[nullable Object]", "__length": 3, "__items": [88, "hello", null]}} + +# Nit: + 1111 qwer> + +# Json: +{"__kind": "obj", "__id": 0, "__class": "B", "b": false, "c": {"__kind": "char", "__val": "b"}, "f": 123.123, "i": 2345, "s": "hjkl", "n": null, "array": {"__kind": "obj", "__id": 1, "__class": "Array[nullable Object]", "__length": 3, "__items": [88, "hello", null]}, "ii": 1111, "ss": "qwer"} + +# Nit: + 1111 qwer>> + +# Json: +{"__kind": "obj", "__id": 0, "__class": "C", "a": {"__kind": "obj", "__id": 1, "__class": "A", "b": true, "c": {"__kind": "char", "__val": "a"}, "f": 0.123, "i": 1234, "s": "asdf", "n": null, "array": {"__kind": "obj", "__id": 2, "__class": "Array[nullable Object]", "__length": 3, "__items": [88, "hello", null]}}, "b": {"__kind": "obj", "__id": 3, "__class": "B", "b": false, "c": {"__kind": "char", "__val": "b"}, "f": 123.123, "i": 2345, "s": "hjkl", "n": null, "array": {"__kind": "obj", "__id": 4, "__class": "Array[nullable Object]", "__length": 3, "__items": [88, "hello", null]}, "ii": 1111, "ss": "qwer"}, "aa": {"__kind": "ref", "__id": 1}} + +# Nit: + +<- false> 1111 f" \/> true> + +# Json: +{"__kind": "obj", "__id": 0, "__class": "D", "b": false, "c": {"__kind": "char", "__val": "b"}, "f": 123.123, "i": 2345, "s": "new line ->\n<-", "n": null, "array": {"__kind": "obj", "__id": 1, "__class": "Array[nullable Object]", "__length": 3, "__items": [88, "hello", null]}, "ii": 1111, "ss": "\tf\"\r\\\/", "d": {"__kind": "ref", "__id": 0}} + diff --git a/tests/sav/test_serialization_alt5.res b/tests/sav/test_serialization_alt5.res new file mode 100644 index 0000000..d1b73a6 --- /dev/null +++ b/tests/sav/test_serialization_alt5.res @@ -0,0 +1,26 @@ +alt/test_serialization_alt5.nit:22,1--47,3: Warning: duplicated annotation `serialize`. +# Nit: + + +# Json: +{"__kind": "obj", "__id": 0, "__class": "A", "b": true, "c": {"__kind": "char", "__val": "a"}, "f": 0.123, "i": 1234, "s": "asdf", "n": null, "array": {"__kind": "obj", "__id": 1, "__class": "Array[nullable Object]", "__length": 3, "__items": [88, "hello", null]}} + +# Nit: + 1111 qwer> + +# Json: +{"__kind": "obj", "__id": 0, "__class": "B", "b": false, "c": {"__kind": "char", "__val": "b"}, "f": 123.123, "i": 2345, "s": "hjkl", "n": null, "array": {"__kind": "obj", "__id": 1, "__class": "Array[nullable Object]", "__length": 3, "__items": [88, "hello", null]}, "ii": 1111, "ss": "qwer"} + +# Nit: + 1111 qwer>> + +# Json: +{"__kind": "obj", "__id": 0, "__class": "C", "a": {"__kind": "obj", "__id": 1, "__class": "A", "b": true, "c": {"__kind": "char", "__val": "a"}, "f": 0.123, "i": 1234, "s": "asdf", "n": null, "array": {"__kind": "obj", "__id": 2, "__class": "Array[nullable Object]", "__length": 3, "__items": [88, "hello", null]}}, "b": {"__kind": "obj", "__id": 3, "__class": "B", "b": false, "c": {"__kind": "char", "__val": "b"}, "f": 123.123, "i": 2345, "s": "hjkl", "n": null, "array": {"__kind": "obj", "__id": 4, "__class": "Array[nullable Object]", "__length": 3, "__items": [88, "hello", null]}, "ii": 1111, "ss": "qwer"}, "aa": {"__kind": "ref", "__id": 1}} + +# Nit: + +<- false> 1111 f" \/> true> + +# Json: +{"__kind": "obj", "__id": 0, "__class": "D", "b": false, "c": {"__kind": "char", "__val": "b"}, "f": 123.123, "i": 2345, "s": "new line ->\n<-", "n": null, "array": {"__kind": "obj", "__id": 1, "__class": "Array[nullable Object]", "__length": 3, "__items": [88, "hello", null]}, "ii": 1111, "ss": "\tf\"\r\\\/", "d": {"__kind": "ref", "__id": 0}} + diff --git a/tests/test_deserialization.nit b/tests/test_deserialization.nit index 1360bf2..deb8997 100644 --- a/tests/test_deserialization.nit +++ b/tests/test_deserialization.nit @@ -26,6 +26,7 @@ class A var i = 123 var s = "asdf" var n: nullable Int + var password = "p4ssw0rd" is lazy, noserialize init(b: Bool, c: Char, f: Float, i: Int, s: String, n: nullable Int) do @@ -36,7 +37,7 @@ class A self.s = s end - redef fun to_s do return "" + redef fun to_s do return "" end # Sub-class of A diff --git a/tests/test_serialization.nit b/tests/test_serialization.nit index 5517cff..75c7a9d 100644 --- a/tests/test_serialization.nit +++ b/tests/test_serialization.nit @@ -14,16 +14,21 @@ # See the License for the specific language governing permissions and # limitations under the License. +#alt2#module test_serialization_alt2 is serialize + import serialization import json::serialization # Simple class class A - auto_serializable + serialize +#alt5# serialize var b = false - var c: Char - var f: Float + var c: Char#alt2# + #alt2#var c: Char is noserialize + var f: Float#alt4# + #alt4#var f: Float is serialize var i = 123 var s = "asdf" var n: nullable Int @@ -43,7 +48,9 @@ end # Sub-class of A class B - auto_serializable + auto_serializable#alt2##alt3# +#alt2# noserialize +#alt3# noserialize super A var ii: Int