As discussed in #1370, the `u8` suffix has been chosen for Byte literal values, this PR introduces it in the compiler
NOTE: Depends on #1403 for integration
Pull-Request: #1410
Reviewed-by: Alexis Laferrière <alexis.laf@xymus.net>
Reviewed-by: Romain Chanoir <chanoir.romain@courrier.uqam.ca>
Reviewed-by: Jean Privat <jean@pryen.org>
--- /dev/null
+all:
+ $(MAKE) all -C nit
+ $(MAKE) all -C java
--- /dev/null
+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
--- /dev/null
+#!/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
--- /dev/null
+
+/**
+ *
+ * @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;
+ }
+}
--- /dev/null
+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<PointDouble> points = new ArrayList<>();
+ ArrayList<PointDouble> 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<PointDouble> 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<PointDouble> points1 = new ArrayList<>();
+ ArrayList<PointDouble> 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<PointDouble> 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<PointDouble> 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<PointDouble> 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<PointDouble> generatePoints(int nb) {
+ ArrayList<PointDouble> pts = new ArrayList<>();
+ pts = PointDouble.getNPointsOnCircle(100.0, nb);
+ return pts;
+ }
+}
--- /dev/null
+
+/**
+ *
+ * @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;
+ }
+}
--- /dev/null
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+
+/**
+ *
+ * @author romis_000, Johan
+ */
+public class ConvexPolygon {
+
+ private ArrayList<PointDouble> points = new ArrayList<PointDouble>();
+
+ public ConvexPolygon(ArrayList<PointDouble> points) {
+ this.points = points;
+ }
+
+ public ArrayList<PointDouble> 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<PointDouble> points) {
+ Collections.sort(points, new PointXCompare());
+ int n = points.size();
+
+ ArrayList<PointDouble> pl1 = new ArrayList<PointDouble>();
+ ArrayList<PointDouble> pl2 = new ArrayList<PointDouble>();
+ 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<PointDouble> 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;
+ }
+ }
+}
--- /dev/null
+
+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<PointDouble> getNPointsOnCircle(double radius, int n) {
+ ArrayList<PointDouble> 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;
+ }
+}
--- /dev/null
+
+import java.util.Comparator;
+
+/**
+ *
+ * @author romis_000
+ */
+class PointXCompare
+ implements Comparator<PointDouble> {
+
+ @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;
+ }
+ }
+}
--- /dev/null
+
+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> {
+
+ 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);
+}
--- /dev/null
+
+/**
+ * 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);
+ }
+}
--- /dev/null
+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
--- /dev/null
+#This file is part of NIT (http://www.nitlanguage.org).
+#
+# Copyright 2015 Romain Chanoir <romain.chanoir@viacesi.fr>
+#
+# 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
--- /dev/null
+#!/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
# Link between two nodes and associated to a graph
class Link
- auto_serializable
+ serialize
# Type of the nodes in `graph`
type N: Node
# Result from path finding and a walkable path
class AStarPath[N]
- auto_serializable
+ serialize
# Total cost of this path
var total_cost: Int
# Context related to an evocation of pathfinding
class PathContext
- auto_serializable
+ serialize
# Type of the nodes in `graph`
type N: Node
# 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
# A `PathContext` for graphs with `WeightedLink`
class WeightedPathContext
super PathContext
- auto_serializable
+ serialize
redef type L: WeightedLink
# A `Link` with a `weight`
class WeightedLink
super Link
- auto_serializable
+ serialize
# The `weight`, or cost, of this link
var weight: Int
# 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
# 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
# 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]
# 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
#
# 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
# 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
# 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]]
# 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.
#
# Game turn on the client
class ThinGameTurn[G: ThinGame]
- auto_serializable
# Game tick when `self` should act.
var tick: Int is protected writable
# Game turn on the full logic
class GameTurn[G: Game]
super ThinGameTurn[G]
- auto_serializable
# Game that `self` belongs to.
var game: G
# Full game logic
class Game
super ThinGame
- auto_serializable
# Game type used in this implementation.
type G: Game
--- /dev/null
+# This file is part of NIT (http://www.nitlanguage.org).
+#
+# Copyright 2015 Romain Chanoir <romain.chanoir@viacesi.fr>
+#
+# 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
# import json::serialization
#
# class Person
-# auto_serializable
+# serialize
#
# var name: String
# var year_of_birth: Int
# limitations under the License.
# Highly specific, but useful, collections-related classes.
-module more_collections
+module more_collections is serialize
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`.
# assert hm2[2, "not-two"] == null
# ~~~~
class HashMap2[K1, K2, V]
- auto_serializable
private var level1 = new HashMap[K1, HashMap[K2, V]]
# 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]]
# assert dma.default == [65]
# ~~~~
class DefaultMap[K, V]
- auto_serializable
super HashMap[K, V]
# The default value.
# 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.
~~~
# Simple serializable class identifying a human
class Person
- auto_serializable
+ serialize
# First and last name
var name: String
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
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`.
### 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
## 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`.
* 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.
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.
# 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.
#
# `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.
color: #666;
}
-#sidebar .panel-body ul .list-labeled>li {
-}
-
#sidebar .panel-body ul ul ul>li {
font-size: 13px;
color: #999;
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
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.
# 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
# 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`.
#
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.
# The root uses a specific subclass to provide different a different behavior
# than other `DocComposite` elements.
class DocRoot
+ noautoinit
super DocComposite
+ redef var id = "<root>"
+ redef var title = "<root>"
+
# No op for `RootSection`.
redef fun parent=(p) do end
end
# 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
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
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
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
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
# 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
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)
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
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
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
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
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
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
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
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
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
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
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)
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
# 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
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
# 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
# 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
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
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
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
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
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
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
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)
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
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
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
# 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.
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.
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.
# 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
# An article that display the definition text of a MEntity.
class DefinitionArticle
super MEntityArticle
+
+ redef var is_hidden = false
end
# The main project article.
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
# 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
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 ": "
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
# Level <hX> 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"
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
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.
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 "<div class='container-fluid'>"
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
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
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
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?
#
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
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"
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.
#
redef fun render_body do
addn "<div class=\"text-center\">"
- addn " <img src='{id}.png' usemap='#{id}' style='margin:auto'"
- addn " alt='{graph_title}'/>"
+ addn " <img src='{graph_id}.png' usemap='#{graph_id}' style='margin:auto'"
+ addn " alt='{title or else ""}'/>"
add map
addn "</div>"
end
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)
# 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
end
end
- fun generate_serialization_method(nclassdef: AClassdef)
+ fun generate_serialization_method(nclassdef: AClassdef, per_attribute: Bool)
do
var npropdefs = nclassdef.n_propdefs
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
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
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
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
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
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
-Runtime error: Aborted (../lib/serialization/serialization.nit:109)
+Runtime error: Aborted (../lib/serialization/serialization.nit:111)
# Nit:
-<A: true a 0.123 1234 asdf false>
+<A: true a 0.123 1234 asdf false p4ssw0rd>
# 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:
-<A: true a 0.123 1234 asdf false>
+<A: true a 0.123 1234 asdf false p4ssw0rd>
# Nit:
-<B: <A: false b 123.123 2345 hjkl false> 1111 qwer>
+<B: <A: false b 123.123 2345 hjkl false p4ssw0rd> 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:
-<B: <A: false b 123.123 2345 hjkl false> 1111 qwer>
+<B: <A: false b 123.123 2345 hjkl false p4ssw0rd> 1111 qwer>
# Nit:
-<C: <A: true a 0.123 1234 asdf false> <B: <A: false b 123.123 2345 hjkl false> 1111 qwer>>
+<C: <A: true a 0.123 1234 asdf false p4ssw0rd> <B: <A: false b 123.123 2345 hjkl false p4ssw0rd> 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:
-<C: <A: true a 0.123 1234 asdf false> <B: <A: false b 123.123 2345 hjkl false> 1111 qwer>>
+<C: <A: true a 0.123 1234 asdf false p4ssw0rd> <B: <A: false b 123.123 2345 hjkl false p4ssw0rd> 1111 qwer>>
# Nit:
<D: <B: <A: false b 123.123 2345 new line ->
-<- false> 1111 f"\r\/> true>
+<- false p4ssw0rd> 1111 f"\r\/> 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:
<D: <B: <A: false b 123.123 2345 new line ->
-<- false> 1111 f"\r\/> true>
+<- false p4ssw0rd> 1111 f"\r\/> true>
Error: doesn't know how to deserialize class "Array"
--- /dev/null
+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:
+<A: true a 0.123 1234 asdf false>
+
+# 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:
+<B: <A: false b 123.123 2345 hjkl false> 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:
+<C: <A: true a 0.123 1234 asdf false> <B: <A: false b 123.123 2345 hjkl false> 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:
+<D: <B: <A: false b 123.123 2345 new line ->
+<- false> 1111 f"\r\/> 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}}
+
--- /dev/null
+alt/test_serialization_alt3.nit:49,1--68,3: Warning: superfluous use of `noserialize`.
+# Nit:
+<A: true a 0.123 1234 asdf false>
+
+# 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:
+<B: <A: false b 123.123 2345 hjkl false> 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:
+<C: <A: true a 0.123 1234 asdf false> <B: <A: false b 123.123 2345 hjkl false> 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:
+<D: <B: <A: false b 123.123 2345 new line ->
+<- false> 1111 f"\r\/> 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}}
+
--- /dev/null
+alt/test_serialization_alt4.nit:29,2--31,26: Warning: superfluous use of `serialize`.
+# Nit:
+<A: true a 0.123 1234 asdf false>
+
+# 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:
+<B: <A: false b 123.123 2345 hjkl false> 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:
+<C: <A: true a 0.123 1234 asdf false> <B: <A: false b 123.123 2345 hjkl false> 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:
+<D: <B: <A: false b 123.123 2345 new line ->
+<- false> 1111 f"\r\/> 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}}
+
--- /dev/null
+alt/test_serialization_alt5.nit:22,1--47,3: Warning: duplicated annotation `serialize`.
+# Nit:
+<A: true a 0.123 1234 asdf false>
+
+# 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:
+<B: <A: false b 123.123 2345 hjkl false> 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:
+<C: <A: true a 0.123 1234 asdf false> <B: <A: false b 123.123 2345 hjkl false> 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:
+<D: <B: <A: false b 123.123 2345 new line ->
+<- false> 1111 f"\r\/> 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}}
+
# Nit:
-<A: true a 0.123 1234 asdf false>
+<A: true a 0.123 1234 asdf false p4ssw0rd>
# 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:
-<A: true a 0.123 1234 asdf false>
+<A: true a 0.123 1234 asdf false p4ssw0rd>
# Nit:
-<B: <A: false b 123.123 2345 hjkl false> 1111 qwer>
+<B: <A: false b 123.123 2345 hjkl false p4ssw0rd> 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:
-<B: <A: false b 123.123 2345 hjkl false> 1111 qwer>
+<B: <A: false b 123.123 2345 hjkl false p4ssw0rd> 1111 qwer>
# Nit:
-<C: <A: true a 0.123 1234 asdf false> <B: <A: false b 123.123 2345 hjkl false> 1111 qwer>>
+<C: <A: true a 0.123 1234 asdf false p4ssw0rd> <B: <A: false b 123.123 2345 hjkl false p4ssw0rd> 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:
-<C: <A: true a 0.123 1234 asdf false> <B: <A: false b 123.123 2345 hjkl false> 1111 qwer>>
+<C: <A: true a 0.123 1234 asdf false p4ssw0rd> <B: <A: false b 123.123 2345 hjkl false p4ssw0rd> 1111 qwer>>
# Nit:
<D: <B: <A: false b 123.123 2345 new line ->
-<- false> 1111 f"\r\/> true>
+<- false p4ssw0rd> 1111 f"\r\/> 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:
<D: <B: <A: false b 123.123 2345 new line ->
-<- false> 1111 f"\r\/> true>
+<- false p4ssw0rd> 1111 f"\r\/> true>
# Nit:
-<A: true a 0.123 1234 asdf false>
+<A: true a 0.123 1234 asdf false p4ssw0rd>
# 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:
-<A: true a 0.123 1234 asdf false>
+<A: true a 0.123 1234 asdf false p4ssw0rd>
# Nit:
-<B: <A: false b 123.123 2345 hjkl false> 1111 qwer>
+<B: <A: false b 123.123 2345 hjkl false p4ssw0rd> 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:
-<B: <A: false b 123.123 2345 hjkl false> 1111 qwer>
+<B: <A: false b 123.123 2345 hjkl false p4ssw0rd> 1111 qwer>
# Nit:
-<C: <A: true a 0.123 1234 asdf false> <B: <A: false b 123.123 2345 hjkl false> 1111 qwer>>
+<C: <A: true a 0.123 1234 asdf false p4ssw0rd> <B: <A: false b 123.123 2345 hjkl false p4ssw0rd> 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:
-<C: <A: true a 0.123 1234 asdf false> <B: <A: false b 123.123 2345 hjkl false> 1111 qwer>>
+<C: <A: true a 0.123 1234 asdf false p4ssw0rd> <B: <A: false b 123.123 2345 hjkl false p4ssw0rd> 1111 qwer>>
# Nit:
<D: <B: <A: false b 123.123 2345 new line ->
-<- false> 1111 f"\r\/> true>
+<- false p4ssw0rd> 1111 f"\r\/> 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:
<D: <B: <A: false b 123.123 2345 new line ->
-<- false> 1111 f"\r\/> true>
+<- false p4ssw0rd> 1111 f"\r\/> true>
# Nit:
<E: a: hello, 1234, 123.4; b: hella, 2345, 234.5>
# Nit:
-<A: true a 0.123 1234 asdf false>
+<A: true a 0.123 1234 asdf false p4ssw0rd>
# Json:
{"b": true, "c": "a", "f": 0.123, "i": 1234, "s": "asdf", "n": null}
# Nit:
-<B: <A: false b 123.123 2345 hjkl false> 1111 qwer>
+<B: <A: false b 123.123 2345 hjkl false p4ssw0rd> 1111 qwer>
# Json:
{"b": false, "c": "b", "f": 123.123, "i": 2345, "s": "hjkl", "n": null, "ii": 1111, "ss": "qwer"}
# Nit:
-<C: <A: true a 0.123 1234 asdf false> <B: <A: false b 123.123 2345 hjkl false> 1111 qwer>>
+<C: <A: true a 0.123 1234 asdf false p4ssw0rd> <B: <A: false b 123.123 2345 hjkl false p4ssw0rd> 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:
<D: <B: <A: false b 123.123 2345 new line ->
-<- false> 1111 f"\r\/> true>
+<- false p4ssw0rd> 1111 f"\r\/> true>
# Json:
{"b": false, "c": "b", "f": 123.123, "i": 2345, "s": "new line ->\n<-", "n": null, "ii": 1111, "ss": "\tf\"\r\\\/", "d": null}
--- /dev/null
+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:
+<A: true a 0.123 1234 asdf false>
+
+# 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:
+<B: <A: false b 123.123 2345 hjkl false> 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:
+<C: <A: true a 0.123 1234 asdf false> <B: <A: false b 123.123 2345 hjkl false> 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:
+<D: <B: <A: false b 123.123 2345 new line ->
+<- false> 1111 f"\r\/> 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}}
+
--- /dev/null
+alt/test_serialization_alt3.nit:49,1--68,3: Warning: superfluous use of `noserialize`.
+# Nit:
+<A: true a 0.123 1234 asdf false>
+
+# 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:
+<B: <A: false b 123.123 2345 hjkl false> 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:
+<C: <A: true a 0.123 1234 asdf false> <B: <A: false b 123.123 2345 hjkl false> 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:
+<D: <B: <A: false b 123.123 2345 new line ->
+<- false> 1111 f"\r\/> 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}}
+
--- /dev/null
+alt/test_serialization_alt4.nit:29,2--31,26: Warning: superfluous use of `serialize`.
+# Nit:
+<A: true a 0.123 1234 asdf false>
+
+# 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:
+<B: <A: false b 123.123 2345 hjkl false> 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:
+<C: <A: true a 0.123 1234 asdf false> <B: <A: false b 123.123 2345 hjkl false> 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:
+<D: <B: <A: false b 123.123 2345 new line ->
+<- false> 1111 f"\r\/> 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}}
+
--- /dev/null
+alt/test_serialization_alt5.nit:22,1--47,3: Warning: duplicated annotation `serialize`.
+# Nit:
+<A: true a 0.123 1234 asdf false>
+
+# 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:
+<B: <A: false b 123.123 2345 hjkl false> 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:
+<C: <A: true a 0.123 1234 asdf false> <B: <A: false b 123.123 2345 hjkl false> 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:
+<D: <B: <A: false b 123.123 2345 new line ->
+<- false> 1111 f"\r\/> 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}}
+
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
self.s = s
end
- redef fun to_s do return "<A: {b} {c} {f} {i} {s} {n != null}>"
+ redef fun to_s do return "<A: {b} {c} {f} {i} {s} {n != null} {password}>"
end
# Sub-class of A
# 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
# Sub-class of A
class B
- auto_serializable
+ auto_serializable#alt2##alt3#
+#alt2# noserialize
+#alt3# noserialize
super A
var ii: Int