Compare commits

...

2 Commits

  1. 2
      Computergrafiek Project/graphics_project_21-22-Danacus
  2. 137
      Gvdi/notes.md
  3. 21
      MCS/idp/Schur/schur.idp
  4. 18
      MCS/idp/Scienceweek/graphColoring/coloring.idp
  5. 50
      MCS/idp/Scienceweek/graphColoring/coloring_draw.idp
  6. 47
      MCS/idp/Scienceweek/graphColoring/coloring_instance_1.idp
  7. 8
      MCS/idp/Scienceweek/graphColoring/coloring_oplossing.aidp
  8. 921
      MCS/idp/Scienceweek/graphColoring/idpd3/JSON.lua
  9. 715
      MCS/idp/Scienceweek/graphColoring/idpd3/dkjson.lua
  10. 395
      MCS/idp/Scienceweek/graphColoring/idpd3/idpd3_browser.lua
  11. 151
      MCS/idp/Scienceweek/graphColoring/idpd3/idpd3_check.lua
  12. 90
      MCS/idp/Scienceweek/graphColoring/idpd3/idpd3_in.lua
  13. 159
      MCS/idp/Scienceweek/graphColoring/idpd3/idpd3_out.lua
  14. 82
      MCS/idp/Scienceweek/graphColoring/idpd3/idpd3_voc.idp
  15. 43
      MCS/idp/Scienceweek/graphColoring/idpd3/logDispatch.lua
  16. 61
      MCS/idp/Scienceweek/graphColoring/idpd3/logPrintTime.lua
  17. 23
      MCS/idp/Scienceweek/graphColoring/idpd3/run.idp
  18. 30
      MCS/idp/Scienceweek/graphColoring/idpd3/timer.lua
  19. 36
      MCS/idp/Scienceweek/graphColoring/idpd3/tprint.lua
  20. 90
      MCS/idp/Scienceweek/hanoi/hanoi.idp
  21. 46
      MCS/idp/Scienceweek/hanoi/hanoi_draw.idp
  22. 30
      MCS/idp/Scienceweek/hanoi/hanoi_instance_1.idp
  23. 29
      MCS/idp/Scienceweek/hanoi/hanoi_instance_2.idp
  24. 30
      MCS/idp/Scienceweek/hanoi/hanoi_solution.aidp
  25. 921
      MCS/idp/Scienceweek/hanoi/idpd3/JSON.lua
  26. 715
      MCS/idp/Scienceweek/hanoi/idpd3/dkjson.lua
  27. 395
      MCS/idp/Scienceweek/hanoi/idpd3/idpd3_browser.lua
  28. 151
      MCS/idp/Scienceweek/hanoi/idpd3/idpd3_check.lua
  29. 90
      MCS/idp/Scienceweek/hanoi/idpd3/idpd3_in.lua
  30. 159
      MCS/idp/Scienceweek/hanoi/idpd3/idpd3_out.lua
  31. 82
      MCS/idp/Scienceweek/hanoi/idpd3/idpd3_voc.idp
  32. 43
      MCS/idp/Scienceweek/hanoi/idpd3/logDispatch.lua
  33. 61
      MCS/idp/Scienceweek/hanoi/idpd3/logPrintTime.lua
  34. 23
      MCS/idp/Scienceweek/hanoi/idpd3/run.idp
  35. 30
      MCS/idp/Scienceweek/hanoi/idpd3/timer.lua
  36. 36
      MCS/idp/Scienceweek/hanoi/idpd3/tprint.lua
  37. 921
      MCS/idp/Scienceweek/nqueens/idpd3/JSON.lua
  38. 715
      MCS/idp/Scienceweek/nqueens/idpd3/dkjson.lua
  39. 395
      MCS/idp/Scienceweek/nqueens/idpd3/idpd3_browser.lua
  40. 151
      MCS/idp/Scienceweek/nqueens/idpd3/idpd3_check.lua
  41. 90
      MCS/idp/Scienceweek/nqueens/idpd3/idpd3_in.lua
  42. 159
      MCS/idp/Scienceweek/nqueens/idpd3/idpd3_out.lua
  43. 82
      MCS/idp/Scienceweek/nqueens/idpd3/idpd3_voc.idp
  44. 43
      MCS/idp/Scienceweek/nqueens/idpd3/logDispatch.lua
  45. 61
      MCS/idp/Scienceweek/nqueens/idpd3/logPrintTime.lua
  46. 23
      MCS/idp/Scienceweek/nqueens/idpd3/run.idp
  47. 30
      MCS/idp/Scienceweek/nqueens/idpd3/timer.lua
  48. 36
      MCS/idp/Scienceweek/nqueens/idpd3/tprint.lua
  49. 35
      MCS/idp/Scienceweek/nqueens/nqueens.idp
  50. 53
      MCS/idp/Scienceweek/nqueens/nqueens_draw.idp
  51. 20
      MCS/idp/Scienceweek/nqueens/nqueens_instance_1.idp
  52. 19
      MCS/idp/Scienceweek/nqueens/nqueens_instance_2.idp
  53. 19
      MCS/idp/Scienceweek/nqueens/nqueens_instance_3.idp
  54. 13
      MCS/idp/Scienceweek/nqueens/nqueens_solution.aidp
  55. 137
      MCS/idp/Scienceweek/roster/draw.idp
  56. 921
      MCS/idp/Scienceweek/roster/idpd3/JSON.lua
  57. 715
      MCS/idp/Scienceweek/roster/idpd3/dkjson.lua
  58. 395
      MCS/idp/Scienceweek/roster/idpd3/idpd3_browser.lua
  59. 151
      MCS/idp/Scienceweek/roster/idpd3/idpd3_check.lua
  60. 90
      MCS/idp/Scienceweek/roster/idpd3/idpd3_in.lua
  61. 159
      MCS/idp/Scienceweek/roster/idpd3/idpd3_out.lua
  62. 82
      MCS/idp/Scienceweek/roster/idpd3/idpd3_voc.idp
  63. 43
      MCS/idp/Scienceweek/roster/idpd3/logDispatch.lua
  64. 61
      MCS/idp/Scienceweek/roster/idpd3/logPrintTime.lua
  65. 23
      MCS/idp/Scienceweek/roster/idpd3/run.idp
  66. 30
      MCS/idp/Scienceweek/roster/idpd3/timer.lua
  67. 36
      MCS/idp/Scienceweek/roster/idpd3/tprint.lua
  68. 153
      MCS/idp/Scienceweek/roster/instance_1.idp
  69. 67
      MCS/idp/Scienceweek/roster/roster.idp
  70. 28
      MCS/idp/Scienceweek/roster/solution.aidp
  71. 921
      MCS/idp/Scienceweek/sudoku/idpd3/JSON.lua
  72. 715
      MCS/idp/Scienceweek/sudoku/idpd3/dkjson.lua
  73. 395
      MCS/idp/Scienceweek/sudoku/idpd3/idpd3_browser.lua
  74. 151
      MCS/idp/Scienceweek/sudoku/idpd3/idpd3_check.lua
  75. 90
      MCS/idp/Scienceweek/sudoku/idpd3/idpd3_in.lua
  76. 159
      MCS/idp/Scienceweek/sudoku/idpd3/idpd3_out.lua
  77. 82
      MCS/idp/Scienceweek/sudoku/idpd3/idpd3_voc.idp
  78. 43
      MCS/idp/Scienceweek/sudoku/idpd3/logDispatch.lua
  79. 61
      MCS/idp/Scienceweek/sudoku/idpd3/logPrintTime.lua
  80. 23
      MCS/idp/Scienceweek/sudoku/idpd3/run.idp
  81. 30
      MCS/idp/Scienceweek/sudoku/idpd3/timer.lua
  82. 36
      MCS/idp/Scienceweek/sudoku/idpd3/tprint.lua
  83. 47
      MCS/idp/Scienceweek/sudoku/sudoku.idp
  84. 55
      MCS/idp/Scienceweek/sudoku/sudoku_draw.idp
  85. 23
      MCS/idp/Scienceweek/sudoku/sudoku_instance_1.idp
  86. 24
      MCS/idp/Scienceweek/sudoku/sudoku_instance_2.idp
  87. 18
      MCS/idp/Scienceweek/sudoku/sudoku_solution.aidp
  88. 2
      Swarch/sa-project

@ -1 +1 @@
Subproject commit b16362d5ac9d252d09e4fb49ee8cc497c59d6f1d
Subproject commit 51181bb6fd45fc5fc7ad0046349d4597e8edbfbd

@ -0,0 +1,137 @@
# Determinisme
Volgens mij is er geen verschil tussen natuurwetten en governing laws, of tussen mind en matter in zekere zin.
Alles wat gebeurt kan je in principe verklaren aan de hand van natuurwetten. Zo is bijvoorbeeld het feit
dat ik nu deze tekst schrijf een gevolg van een hele lange sequentie van evenementen die hiertoe geleid hebben.
Van het bestaan van het universum tot evolutie van de mens, mijn geboorte en hoe ik opgegroeid ben. Dit heeft geleid
tot de creatie van verbindingen in mijn brein, waardoor elektronen op zodanige manier vloeien dat de spieren in mijn
hand toetsen op mijn toetsenbord indrukken. Dit allemaal door het toepassen van natuurwetten.
Maar dan vraag ik mij af waar dit begon. Er moet ergens een "seed" zijn, zodat wanneer we er natuurwetten
op toepassen we in de huidige toestand komen. Dit geeft aanleiding tot het idee dat er een zekere
willekeur in het universum moet zitten, de initiële "seed", en dan zou je kunnen concluderen dat het universum niet deterministisch
kan zijn en de huidige toestand niet noodzakelijk een louter deterministisch gevolg van het toepassen van natuurwetten is.
Of misschien maken wij als mens de fout om te grijpen naar het concept van begin en einde. Misschien is het universum nooit
begonnen en was het er altijd al. Een idee dat moeilijk te vatten is voor de mens, maar ons eventueel wel toelaat
om het concept van niet-deteminisme te weigeren. Sinds er geen beginpunt is, kan de "seed" ook een gevolg zijn
van het toepassen van natuurwetten om de voorgaande toestand. Als tijd geen beginpunt heeft, kan men dan concluderen
dat voor elke toestand van het universum er een tijdstip is waarop het universum in die toestand is?
# Tijd
Ik heb een bizar idee van wat tijd is. Ik denk dat het universum op elk punt in de tijd splitst in (bijna) oneindig veel parallelle
universums. Dus wanneer ik bijvoorbeeld een glas water drink, is er ook een universum waarin ik dat niet doe. Wanneer ik sterf is er
ook een universum waarin ik niet sterf. Maar dit gebeurt op een oneindig klein niveau. Deze splitsing gebeurt niet op discrete tijdstippen, maar gebeurt continu.
Ook volgt volgens mij iedereen een andere tijdlijn door deze splitsende universums. Maar wat dicteert dan welke tijdlijn ik volg? Zijn er
oneindig veel verschillende versies van mijn die allemaal een eigen tijdlijn volgen. Als ik jou zie sterven, ben jij dan gestorven in jouw tijdlijn,
of enkel in mijn tijdlijn? Misschien leef jij gewoon verder en zie ik de versie van jij in mijn universum gewoon sterven?
Volgens deze redenering is het mogelijk dat ik zelf nooit zal sterven, of toch niet in de tijdlijn die ik volg, aangezien ik
mijzelf nog niet heb zien sterven in mijn tijdlijn. Ik heb andere mensen zien sterven in mijn tijdlijn, maar dat wil niet zeggen
dat zij zelf sterven in hun tijdlijn.
Deze redenering geeft aanleiding tot een idealistische zienswijze waarin je een geest hebt die bepaalt welke tijdlijn je volgt.
# Wetten
Ik begrijp eigenlijk niet waarom er een expliciet onderscheid gemaakt wordt tussen natuurwetten en governing laws.
Natuurwetten zijn wetten, dingen die altijd waar zijn. Governing laws zijn geen wetten, maar gewoon uitspraken van
mensen, net zoals de uitspraak "ik vind de kleur blauw mooi". Ik begrijp niet wat de relevantie is van
deze vergelijking, deze twee concepten hebben gewoon niets met elkaar te maken. Het is alsof je de lengte van mijn
voet zou vergelijken met de kleur van de tafel. Er valt gewoon niets te vergelijken.
# Church
Ik vind materialistische zienswijze van Church voor de oorlog interessant:
> For Church, mathematical entities were “fictions” and “part of an abstract structure constructed by us to enable us to understand reality”
Ik vind het wel vreemd dat Church dan Turing interpreteert als mechanisch proces en niet als wiskundig proces. Ook
al beweert hij dat wiskunde fictief is. Ik zie geen reden waarom hij de theorie van Turing niet mathematisch zou kunnen
opvatten, als een abstracte structuur die ons toelaat de realiteit te begrijpen.
# Mijn visie
Ik heb het gevoel dat ik de hele tijd spring tussen verschillende zienswijzen, maar zal trachten een consistente zienswijze te formuleren.
Ik denk dat er een correcte manier is om over het hele universum te redeneren. Een soort van "logica" die volledig het universum kan beschrijven
aan de hand van "natuurwetten". Ik ben er echter ook van overtuigd dat de huidige manier van redeneren ("formele systemen") en de huidige kennis
van "natuurwetten" niet voldoende is om het universum correct te beschrijven. In die zin is de wiskunde steeds slechts een benadering.
Op zoek gaan naar een volledige en correcte manier is zeer moeilijk omdat we dit mogelijks niet zullen kunnen vatten als mensen.
De huidige wiskunde is een benadering of abstractie van de realiteit die vatbaar is voor de mens en zal waarschijnlijk nooit perfect zijn.
Dit wil niet zeggen dat de wiskunde niet nuttig is om bepaalde dingen te bewijzen. Onder zekere veronderstelling zijn deze resultaten
correct, maar er zullen altijd veronderstellingen zijn. Dit zorgt voor een soort van "gap" tussen de abstract wiskunde/logica en de
fysische realiteit. In de praktische zin ben ik dus eerder een dualist, maar ik geloof wel dat het in theorie mogelijk is
om die "gap" te sluiten. Ik weet echter niet of dit mogelijk is met de huidige kennis en breincapaciteit van de mens.
Ik begrijp waarom Wittgenstein het misleidend vind om wiskundige proposities te vergelijken met proposities uit de fysica, maar ik
vind persoonlijk wel dat het nuttig kan zijn om wiskundige resultaten proberen toe te passen in de fysische werkelijkheid,
ook al is dit niet correct. Het geeft ons een idee van de grootte van de "gap" tussen wiskunde en de fysische realiteit.
Dit kunnen we dan gebruiken om bepaalde wiskundige abstracties aan te passen of een nieuwe logica te vinden die beter
aansluit bij de realiteit.
Ons puur baseren op fysische realiteit om resultaten te vinden kan leiden tot problemen zoals die theorie van Newton. Daar bleek
later dat deze theorie enkel geldig is onder bepaalde veronderstellingen. Einstein moest abstract kunnen denken in de wiskunde
om tot een algemener resultaat te komen. Relativiteitstheorie zou de mens nooit zo snel gevonden kunnen hebben als we ons enkel
zouden baseren op fysische waarnemingen.
Ik ben het ergens ook wel eens met Wittgenstein dat wiskunde niets ontdekt en enkel maar dingen uit vindt. Maar ik vind die uitvindingen
persoonlijk wel nuttig om te kunnen redeneren over een abstractie van de realiteit.
Anderzijds ben ik het deels eens met Turing en Russel:
> But Turing was not to be persuaded. For him, as for Russell and for most professional mathematicians, the beauty of mathematics, its very ‘charm’, lay precisely in its power to provide, in an otherwise uncertain world, unassailable truths.”
Wiskunde geeft ons zekere waarheden, maar ik denk dat als we deze waarheden willen toepassen op de realiteit we er ons van bewust moeten zijn
dat de wiskunde in de huidige toestand slechts een abstractie en benadering van de realiteit is. Ik geloof wel dat er een wiskunde of logica
bestaat die ons wel toelaat om deze waarheden door te trekken naar de fysische werkelijkheid, maar daarvoor moet de "gap" gesloten worden.
Toch vind ik dat Wittgenstein dan wel weer een punt heeft. Je kan een brug ontwerpen op basis van "perfecte" calculus die toch instort doordat er een
vliegtuig op instort. In onze wiskunde hebben we bepaalde abstracties en veronderstellingen gemaakt, iets wat we moeten doen om het realistisch
te maken om de wiskunde te gebruiken. Een echt correcte en volledige wiskunde die echt waterdicht zou dit allemaal in rekening gebracht hebben,
maar zou zo moeilijk zijn om mee te werken voor ons mensen.
Ik ben het dus eens met Russel in de zin dat er een wiskunde is waarvoor er een 1-op-1 mapping is met de fysische werkelijkheid. Onze "vereenvoudigde"
wiskunde is volgens mij gewoon niet die wiskunde. Maar de "echte" perfecte wiskunde is ondenkbaar complex en valt niet in te redeneren.
Aangezien de huidige wiskunde slechts een benadering is van de realiteit moet je dus oppassen wanneer je het in de praktijk wil toepassen en
is het soms beter om "de ingenieur uit te hangen en wat te spelen met de fysische realiteit" in plaats van trachten te bewijzen wat er in de realiteit gebeurt.
Dat gezegd denk ik dat als je de juiste veronderstellingen maakt over de realiteit je onze beperkte wiskunde wel goed in de praktijk kan toepassen.
Bijvoorbeeld als je een perfecte brug ontwerpt aan de hand van de wiskunde, dan maak je direct enkele veronderstellingen, zoals de veronderstelling
dat er geen meteoor op de brug gaat vallen.
Als dat dan toch gebeurt is dat niet omdat er iets mis is met de wiskunde, maar omdat je noodzakelijkerwijs
veronderstellingen hebt gemaakt om de wiskunde toe te kunnen passen.
Mijn punt is dat onder de juiste veronderstellingen je de wiskunde wel kan gebruiken om te bepalen hoe je engineering gaat doen.
Dit wordt dan wel gevaarlijk als je een computer gaat ontwerpen op basis van het model van een Turingmachine omdat je dan verondersteld
dat je oneindig veel geheugen hebt wat niet het geval is. Ook heb je abstractie gemaakt van allerlei concepten zoals snelheid en
enegieverbruik en productiekost. Die dingen kon je ook allemaal wiskundig formaliseren, maar als je dat allemaal tegelijk probeert te formaliseren wordt
het veel te moeilijk om de logisch perfecte computer te bepalen, vooral als je alles probeert terug te brengen naar natuurwetten en logische gevolgen daarvan.
Dus is het praktischer om de ingenieur uit te hangen en maar wat te proberen en wat af te wegen op basis van wat lijkt te werken in de realiteit.
"that one and only logical system" waar Russel het over heeft zou volgens mij dan wel rekening houden met alle factoren en daar zou de perfecte
computer uit komen. Ik geloof dat zo een systeem bestaat, maar ik denk niet dat de mens dit ooit zal vinden en kunnen vatten.
Ik denk dus niet dat de calculus van Frege of Principia Mathematica van Russel dit perfecte logische systeem zijn.
Wanneer Dijkstra bewijst dat een programma correct is maakt hij een hele hoop veronderstellingen over de omgeving waarin het programma wordt
uitgevoerd en de invoer die het programma krijgt. Maar in de realiteit is de invoer het hele universum. De correctheid van een programma
bewijzen met als invoer het hele universum is praktisch onmogelijk met de huidige formele systemen, maar dat zou misschien wel kunnen
met de perfecte wiskunde. Helaas kom je dan tot de conclusie dat geen enkel programma correct is aangezien er altijd een atoombom kan ontploffen
die de computer kapot maakt tijdens de uitvoering. Dat zou geen interessant resultaat zijn. De veronderstellingen die je maakt zijn
dus wel nodig om enige vorm van correctheid te bewijzen en dat lijkt mij op zich niet volledig nutteloos.

@ -1,21 +0,0 @@
/*************
Schur
*************/
vocabulary V {
type number isa int
type partition isa int
maxNumber : number
inPartition(number, partition)
}
theory T:V {
!n [number]: n < maxNumber.
}
structure S:V {
maxNumber = 70
}

@ -1,18 +0,0 @@
vocabulary V{
type Color
type Area
Border(Area,Area)
Coloring(Area):Color
}
theory T : V {
// Two adjacent countries can not have the same color
//TODO add this constraint
!a,b: Border(a,b) => Coloring(a) ~= Coloring(b).
}
include "coloring_draw.idp"
include "coloring_instance_1.idp"
include "coloring_oplossing.aidp"
include "idpd3/run.idp"

@ -1,50 +0,0 @@
include "idpd3/idpd3_voc.idp"
vocabulary V_out {
extern vocabulary idpd3::V_out
extern vocabulary V
type isLabel constructed from {t, f}
toKey(Area, isLabel) : key
toLink(Area, Area) : key
error(Area)
x(Area) : width
y(Area) : width
toLabel(Area) : label
color(Color) : color
}
theory T_D3 : V_out {
{
error(g1) <- Coloring(g1) = k & Coloring(g2) = k & Border(g1, g2).
error(g1) <- Coloring(g1) = k & Coloring(g2) = k & Border(g2, g1).
}
{
d3_type(1, k) = circ <- toKey(g, f) = k.
d3_circ_r(1, k) = 2 <- toKey(g, f) = k.
d3_x(1, k) = x <- false.
d3_y(1, k) = y <- false.
d3_color(1, k) = c <- toKey(g, f) = k & c = color(Coloring(g)).
d3_node(1, k) <- toKey(g, f) = k.
d3_type(1, k) = link <- toLink(g1, g2) = k & Border(g1, g2).
d3_link_from(1, k) = k1 <- toLink(g1, g2) = k & Border(g1, g2) & toKey(g1, f) = k1.
d3_link_to(1, k) = k1 <- toLink(g1, g2) = k & Border(g1, g2) & toKey(g2, f) = k1.
d3_link_width(1, k) = 5 <- toLink(g1, g2) = k & Border(g1, g2).
d3_color(1, k) = "red" <- toLink(g1, g2) = k & Border(g1, g2) & Coloring(g1) = Coloring(g2).
d3_color(1, k) = "gray" <- toLink(g1, g2) = k & Border(g1, g2) & Coloring(g1) ~= Coloring(g2).
/*d3_type(1, k) = text <- toKey(g, t) = k.
d3_label(1, k) = toLabel(g) <- toKey(g, t) = k.
d3_x(1, k) = 2 * y(g) + 1 <- toKey(g, t) = k.
d3_y(1, k) = 2 * x(g) <- toKey(g, t) = k.
d3_color(1, k) = "black" <- toKey(g, t) = k./**/
d3_rect_height(1, x) = y <- false.
d3_rect_width(1, x) = y <- false.
d3_text_size(1, x) = y <- false.
}
!t : ! x: d3_width(t) = x => ~?y : x<y.
!t : ! x: d3_height(t) = x => ~?y : x<y.
}

@ -1,47 +0,0 @@
procedure toKey(l, f) {
return l..tostring(f);
}
procedure toLink(g1, g2) {
return "g"..tostring(g1).."-"..tostring(g2);
}
procedure label(g) {
return g;
}
structure S : V_out {
Color = { blue; orange; yellow; green }
Area = { 1..12 }
Border = { 1,2; 1,4; 1,5;
2,3; 2,4;
3,4; 3,7; 3,12;
4,5; 4,6; 4,7;
5,6; 5,8;
6,7; 6,8; 6,9; 6,10;
7,10; 7,11; 7,12;
8,9;
9,10;
10,11;
11,12;}
//idpd3
time = {1}
width = {0..80}
height = {0..80}
color = {"white"; "red"; "orange"; "green"; "blue"; "yellow"; "black"; "gray"}
x = {1,1; 2,3; 3,5; 4,3; 5,1; 6,3; 7,5; 8,1; 9,3; 10,5; 11,7; 12,7}
y = {1,1; 2,0; 3,1; 4,2; 5,3; 6,4; 7,3; 8,5; 9,6; 10,5; 11,4; 12,2}
toKey = procedure toKey
toLink = procedure toLink
color = {
blue, "blue";
orange, "orange";
yellow, "yellow";
green, "green"
}
toLabel = procedure label
}
procedure getExpectedModels() {
return 3;
}

@ -1,8 +0,0 @@
theory T_exp : V {
// Two adjacent countries can not have the same color
!a1, a2:Border(a1,a2) | Border(a2,a1) => Coloring(a1) ~= Coloring(a2).
}
procedure name(){
return "Coloring"
}

@ -1,921 +0,0 @@
-- -*- coding: utf-8 -*-
--
-- Simple JSON encoding and decoding in pure Lua.
--
-- Copyright 2010-2014 Jeffrey Friedl
-- http://regex.info/blog/
--
-- Latest version: http://regex.info/blog/lua/json
--
-- This code is released under a Creative Commons CC-BY "Attribution" License:
-- http://creativecommons.org/licenses/by/3.0/deed.en_US
--
-- It can be used for any purpose so long as the copyright notice above,
-- the web-page links above, and the 'AUTHOR_NOTE' string below are
-- maintained. Enjoy.
--
local VERSION = 20140920.13 -- version history at end of file
local AUTHOR_NOTE = "-[ JSON.lua package by Jeffrey Friedl (http://regex.info/blog/lua/json) version 20140920.13 ]-"
--
-- The 'AUTHOR_NOTE' variable exists so that information about the source
-- of the package is maintained even in compiled versions. It's included in
-- OBJDEF mostly to quiet warnings about unused variables.
--
local OBJDEF = {
VERSION = VERSION,
AUTHOR_NOTE = AUTHOR_NOTE,
}
--
-- Simple JSON encoding and decoding in pure Lua.
-- http://www.json.org/
--
--
-- JSON = (loadfile "JSON.lua")() -- one-time load of the routines
--
-- local lua_value = JSON:decode(raw_json_text)
--
-- local raw_json_text = JSON:encode(lua_table_or_value)
-- local pretty_json_text = JSON:encode_pretty(lua_table_or_value) -- "pretty printed" version for human readability
--
--
-- DECODING
--
-- JSON = (loadfile "JSON.lua")() -- one-time load of the routines
--
-- local lua_value = JSON:decode(raw_json_text)
--
-- If the JSON text is for an object or an array, e.g.
-- { "what": "books", "count": 3 }
-- or
-- [ "Larry", "Curly", "Moe" ]
--
-- the result is a Lua table, e.g.
-- { what = "books", count = 3 }
-- or
-- { "Larry", "Curly", "Moe" }
--
--
-- The encode and decode routines accept an optional second argument, "etc", which is not used
-- during encoding or decoding, but upon error is passed along to error handlers. It can be of any
-- type (including nil).
--
-- With most errors during decoding, this code calls
--
-- JSON:onDecodeError(message, text, location, etc)
--
-- with a message about the error, and if known, the JSON text being parsed and the byte count
-- where the problem was discovered. You can replace the default JSON:onDecodeError() with your
-- own function.
--
-- The default onDecodeError() merely augments the message with data about the text and the
-- location if known (and if a second 'etc' argument had been provided to decode(), its value is
-- tacked onto the message as well), and then calls JSON.assert(), which itself defaults to Lua's
-- built-in assert(), and can also be overridden.
--
-- For example, in an Adobe Lightroom plugin, you might use something like
--
-- function JSON:onDecodeError(message, text, location, etc)
-- LrErrors.throwUserError("Internal Error: invalid JSON data")
-- end
--
-- or even just
--
-- function JSON.assert(message)
-- LrErrors.throwUserError("Internal Error: " .. message)
-- end
--
-- If JSON:decode() is passed a nil, this is called instead:
--
-- JSON:onDecodeOfNilError(message, nil, nil, etc)
--
-- and if JSON:decode() is passed HTML instead of JSON, this is called:
--
-- JSON:onDecodeOfHTMLError(message, text, nil, etc)
--
-- The use of the fourth 'etc' argument allows stronger coordination between decoding and error
-- reporting, especially when you provide your own error-handling routines. Continuing with the
-- the Adobe Lightroom plugin example:
--
-- function JSON:onDecodeError(message, text, location, etc)
-- local note = "Internal Error: invalid JSON data"
-- if type(etc) = 'table' and etc.photo then
-- note = note .. " while processing for " .. etc.photo:getFormattedMetadata('fileName')
-- end
-- LrErrors.throwUserError(note)
-- end
--
-- :
-- :
--
-- for i, photo in ipairs(photosToProcess) do
-- :
-- :
-- local data = JSON:decode(someJsonText, { photo = photo })
-- :
-- :
-- end
--
--
--
--
-- DECODING AND STRICT TYPES
--
-- Because both JSON objects and JSON arrays are converted to Lua tables, it's not normally
-- possible to tell which a JSON type a particular Lua table was derived from, or guarantee
-- decode-encode round-trip equivalency.
--
-- However, if you enable strictTypes, e.g.
--
-- JSON = (loadfile "JSON.lua")() --load the routines
-- JSON.strictTypes = true
--
-- then the Lua table resulting from the decoding of a JSON object or JSON array is marked via Lua
-- metatable, so that when re-encoded with JSON:encode() it ends up as the appropriate JSON type.
--
-- (This is not the default because other routines may not work well with tables that have a
-- metatable set, for example, Lightroom API calls.)
--
--
-- ENCODING
--
-- JSON = (loadfile "JSON.lua")() -- one-time load of the routines
--
-- local raw_json_text = JSON:encode(lua_table_or_value)
-- local pretty_json_text = JSON:encode_pretty(lua_table_or_value) -- "pretty printed" version for human readability
-- On error during encoding, this code calls:
--
-- JSON:onEncodeError(message, etc)
--
-- which you can override in your local JSON object.
--
-- If the Lua table contains both string and numeric keys, it fits neither JSON's
-- idea of an object, nor its idea of an array. To get around this, when any string
-- key exists (or when non-positive numeric keys exist), numeric keys are converted
-- to strings.
--
-- For example,
-- JSON:encode({ "one", "two", "three", SOMESTRING = "some string" }))
-- produces the JSON object
-- {"1":"one","2":"two","3":"three","SOMESTRING":"some string"}
--
-- To prohibit this conversion and instead make it an error condition, set
-- JSON.noKeyConversion = true
--
-- SUMMARY OF METHODS YOU CAN OVERRIDE IN YOUR LOCAL LUA JSON OBJECT
--
-- assert
-- onDecodeError
-- onDecodeOfNilError
-- onDecodeOfHTMLError
-- onEncodeError
--
-- If you want to create a separate Lua JSON object with its own error handlers,
-- you can reload JSON.lua or use the :new() method.
--
---------------------------------------------------------------------------
local isArray = { __tostring = function() return "JSON array" end } isArray.__index = isArray
local isObject = { __tostring = function() return "JSON object" end } isObject.__index = isObject
function OBJDEF:newArray(tbl)
return setmetatable(tbl or {}, isArray)
end
function OBJDEF:newObject(tbl)
return setmetatable(tbl or {}, isObject)
end
local function unicode_codepoint_as_utf8(codepoint)
--
-- codepoint is a number
--
if codepoint <= 127 then
return string.char(codepoint)
elseif codepoint <= 2047 then
--
-- 110yyyxx 10xxxxxx <-- useful notation from http://en.wikipedia.org/wiki/Utf8
--
local highpart = math.floor(codepoint / 0x40)
local lowpart = codepoint - (0x40 * highpart)
return string.char(0xC0 + highpart,
0x80 + lowpart)
elseif codepoint <= 65535 then
--
-- 1110yyyy 10yyyyxx 10xxxxxx
--
local highpart = math.floor(codepoint / 0x1000)
local remainder = codepoint - 0x1000 * highpart
local midpart = math.floor(remainder / 0x40)
local lowpart = remainder - 0x40 * midpart
highpart = 0xE0 + highpart
midpart = 0x80 + midpart
lowpart = 0x80 + lowpart
--
-- Check for an invalid character (thanks Andy R. at Adobe).
-- See table 3.7, page 93, in http://www.unicode.org/versions/Unicode5.2.0/ch03.pdf#G28070
--
if ( highpart == 0xE0 and midpart < 0xA0 ) or
( highpart == 0xED and midpart > 0x9F ) or
( highpart == 0xF0 and midpart < 0x90 ) or
( highpart == 0xF4 and midpart > 0x8F )
then
return "?"
else
return string.char(highpart,
midpart,
lowpart)
end
else
--
-- 11110zzz 10zzyyyy 10yyyyxx 10xxxxxx
--
local highpart = math.floor(codepoint / 0x40000)
local remainder = codepoint - 0x40000 * highpart
local midA = math.floor(remainder / 0x1000)
remainder = remainder - 0x1000 * midA
local midB = math.floor(remainder / 0x40)
local lowpart = remainder - 0x40 * midB
return string.char(0xF0 + highpart,
0x80 + midA,
0x80 + midB,
0x80 + lowpart)
end
end
function OBJDEF:onDecodeError(message, text, location, etc)
if text then
if location then
message = string.format("%s at char %d of: %s", message, location, text)
else
message = string.format("%s: %s", message, text)
end
end
if etc ~= nil then
message = message .. " (" .. OBJDEF:encode(etc) .. ")"
end
if self.assert then
self.assert(false, message)
else
assert(false, message)
end
end
OBJDEF.onDecodeOfNilError = OBJDEF.onDecodeError
OBJDEF.onDecodeOfHTMLError = OBJDEF.onDecodeError
function OBJDEF:onEncodeError(message, etc)
if etc ~= nil then
message = message .. " (" .. OBJDEF:encode(etc) .. ")"
end
if self.assert then
self.assert(false, message)
else
assert(false, message)
end
end
local function grok_number(self, text, start, etc)
--
-- Grab the integer part
--
local integer_part = text:match('^-?[1-9]%d*', start)
or text:match("^-?0", start)
if not integer_part then
self:onDecodeError("expected number", text, start, etc)
end
local i = start + integer_part:len()
--
-- Grab an optional decimal part
--
local decimal_part = text:match('^%.%d+', i) or ""
i = i + decimal_part:len()
--
-- Grab an optional exponential part
--
local exponent_part = text:match('^[eE][-+]?%d+', i) or ""
i = i + exponent_part:len()
local full_number_text = integer_part .. decimal_part .. exponent_part
local as_number = tonumber(full_number_text)
if not as_number then
self:onDecodeError("bad number", text, start, etc)
end
return as_number, i
end
local function grok_string(self, text, start, etc)
if text:sub(start,start) ~= '"' then
self:onDecodeError("expected string's opening quote", text, start, etc)
end
local i = start + 1 -- +1 to bypass the initial quote
local text_len = text:len()
local VALUE = ""
while i <= text_len do
local c = text:sub(i,i)
if c == '"' then
return VALUE, i + 1
end
if c ~= '\\' then
VALUE = VALUE .. c
i = i + 1
elseif text:match('^\\b', i) then
VALUE = VALUE .. "\b"
i = i + 2
elseif text:match('^\\f', i) then
VALUE = VALUE .. "\f"
i = i + 2
elseif text:match('^\\n', i) then
VALUE = VALUE .. "\n"
i = i + 2
elseif text:match('^\\r', i) then
VALUE = VALUE .. "\r"
i = i + 2
elseif text:match('^\\t', i) then
VALUE = VALUE .. "\t"
i = i + 2
else
local hex = text:match('^\\u([0123456789aAbBcCdDeEfF][0123456789aAbBcCdDeEfF][0123456789aAbBcCdDeEfF][0123456789aAbBcCdDeEfF])', i)
if hex then
i = i + 6 -- bypass what we just read
-- We have a Unicode codepoint. It could be standalone, or if in the proper range and
-- followed by another in a specific range, it'll be a two-code surrogate pair.
local codepoint = tonumber(hex, 16)
if codepoint >= 0xD800 and codepoint <= 0xDBFF then
-- it's a hi surrogate... see whether we have a following low
local lo_surrogate = text:match('^\\u([dD][cdefCDEF][0123456789aAbBcCdDeEfF][0123456789aAbBcCdDeEfF])', i)
if lo_surrogate then
i = i + 6 -- bypass the low surrogate we just read
codepoint = 0x2400 + (codepoint - 0xD800) * 0x400 + tonumber(lo_surrogate, 16)
else
-- not a proper low, so we'll just leave the first codepoint as is and spit it out.
end
end
VALUE = VALUE .. unicode_codepoint_as_utf8(codepoint)
else
-- just pass through what's escaped
VALUE = VALUE .. text:match('^\\(.)', i)
i = i + 2
end
end
end
self:onDecodeError("unclosed string", text, start, etc)
end
local function skip_whitespace(text, start)
local _, match_end = text:find("^[ \n\r\t]+", start) -- [http://www.ietf.org/rfc/rfc4627.txt] Section 2
if match_end then
return match_end + 1
else
return start
end
end
local grok_one -- assigned later
local function grok_object(self, text, start, etc)
if text:sub(start,start) ~= '{' then
self:onDecodeError("expected '{'", text, start, etc)
end
local i = skip_whitespace(text, start + 1) -- +1 to skip the '{'
local VALUE = self.strictTypes and self:newObject { } or { }
if text:sub(i,i) == '}' then
return VALUE, i + 1
end
local text_len = text:len()
while i <= text_len do
local key, new_i = grok_string(self, text, i, etc)
i = skip_whitespace(text, new_i)
if text:sub(i, i) ~= ':' then
self:onDecodeError("expected colon", text, i, etc)
end
i = skip_whitespace(text, i + 1)
local new_val, new_i = grok_one(self, text, i)
VALUE[key] = new_val
--
-- Expect now either '}' to end things, or a ',' to allow us to continue.
--
i = skip_whitespace(text, new_i)
local c = text:sub(i,i)
if c == '}' then
return VALUE, i + 1
end
if text:sub(i, i) ~= ',' then
self:onDecodeError("expected comma or '}'", text, i, etc)
end
i = skip_whitespace(text, i + 1)
end
self:onDecodeError("unclosed '{'", text, start, etc)
end
local function grok_array(self, text, start, etc)
if text:sub(start,start) ~= '[' then
self:onDecodeError("expected '['", text, start, etc)
end
local i = skip_whitespace(text, start + 1) -- +1 to skip the '['
local VALUE = self.strictTypes and self:newArray { } or { }
if text:sub(i,i) == ']' then
return VALUE, i + 1
end
local VALUE_INDEX = 1
local text_len = text:len()
while i <= text_len do
local val, new_i = grok_one(self, text, i)
-- can't table.insert(VALUE, val) here because it's a no-op if val is nil
VALUE[VALUE_INDEX] = val
VALUE_INDEX = VALUE_INDEX + 1
i = skip_whitespace(text, new_i)
--
-- Expect now either ']' to end things, or a ',' to allow us to continue.
--
local c = text:sub(i,i)
if c == ']' then
return VALUE, i + 1
end
if text:sub(i, i) ~= ',' then
self:onDecodeError("expected comma or '['", text, i, etc)
end
i = skip_whitespace(text, i + 1)
end
self:onDecodeError("unclosed '['", text, start, etc)
end
grok_one = function(self, text, start, etc)
-- Skip any whitespace
start = skip_whitespace(text, start)
if start > text:len() then
self:onDecodeError("unexpected end of string", text, nil, etc)
end
if text:find('^"', start) then
return grok_string(self, text, start, etc)
elseif text:find('^[-0123456789 ]', start) then
return grok_number(self, text, start, etc)
elseif text:find('^%{', start) then
return grok_object(self, text, start, etc)
elseif text:find('^%[', start) then
return grok_array(self, text, start, etc)
elseif text:find('^true', start) then
return true, start + 4
elseif text:find('^false', start) then
return false, start + 5
elseif text:find('^null', start) then
return nil, start + 4
else
self:onDecodeError("can't parse JSON", text, start, etc)
end
end
function OBJDEF:decode(text, etc)
if type(self) ~= 'table' or self.__index ~= OBJDEF then
OBJDEF:onDecodeError("JSON:decode must be called in method format", nil, nil, etc)
end
if text == nil then
self:onDecodeOfNilError(string.format("nil passed to JSON:decode()"), nil, nil, etc)
elseif type(text) ~= 'string' then
self:onDecodeError(string.format("expected string argument to JSON:decode(), got %s", type(text)), nil, nil, etc)
end
if text:match('^%s*$') then
return nil
end
if text:match('^%s*<') then
-- Can't be JSON... we'll assume it's HTML
self:onDecodeOfHTMLError(string.format("html passed to JSON:decode()"), text, nil, etc)
end
--
-- Ensure that it's not UTF-32 or UTF-16.
-- Those are perfectly valid encodings for JSON (as per RFC 4627 section 3),
-- but this package can't handle them.
--
if text:sub(1,1):byte() == 0 or (text:len() >= 2 and text:sub(2,2):byte() == 0) then
self:onDecodeError("JSON package groks only UTF-8, sorry", text, nil, etc)
end
local success, value = pcall(grok_one, self, text, 1, etc)
if success then
return value
else
-- if JSON:onDecodeError() didn't abort out of the pcall, we'll have received the error message here as "value", so pass it along as an assert.
if self.assert then
self.assert(false, value)
else
assert(false, value)
end
-- and if we're still here, return a nil and throw the error message on as a second arg
return nil, value
end
end
local function backslash_replacement_function(c)
if c == "\n" then
return "\\n"
elseif c == "\r" then
return "\\r"
elseif c == "\t" then
return "\\t"
elseif c == "\b" then
return "\\b"
elseif c == "\f" then
return "\\f"
elseif c == '"' then
return '\\"'
elseif c == '\\' then
return '\\\\'
else
return string.format("\\u%04x", c:byte())
end
end
local chars_to_be_escaped_in_JSON_string
= '['
.. '"' -- class sub-pattern to match a double quote
.. '%\\' -- class sub-pattern to match a backslash
.. '%z' -- class sub-pattern to match a null
.. '\001' .. '-' .. '\031' -- class sub-pattern to match control characters
.. ']'
local function json_string_literal(value)
local newval = value:gsub(chars_to_be_escaped_in_JSON_string, backslash_replacement_function)
return '"' .. newval .. '"'
end
local function object_or_array(self, T, etc)
--
-- We need to inspect all the keys... if there are any strings, we'll convert to a JSON
-- object. If there are only numbers, it's a JSON array.
--
-- If we'll be converting to a JSON object, we'll want to sort the keys so that the
-- end result is deterministic.
--
local string_keys = { }
local number_keys = { }
local number_keys_must_be_strings = false
local maximum_number_key
for key in pairs(T) do
if type(key) == 'string' then
table.insert(string_keys, key)
elseif type(key) == 'number' then
table.insert(number_keys, key)
if key <= 0 or key >= math.huge then
number_keys_must_be_strings = true
elseif not maximum_number_key or key > maximum_number_key then
maximum_number_key = key
end
else
self:onEncodeError("can't encode table with a key of type " .. type(key), etc)
end
end
if #string_keys == 0 and not number_keys_must_be_strings then
--
-- An empty table, or a numeric-only array
--
if #number_keys > 0 then
return nil, maximum_number_key -- an array
elseif tostring(T) == "JSON array" then
return nil
elseif tostring(T) == "JSON object" then
return { }
else
-- have to guess, so we'll pick array, since empty arrays are likely more common than empty objects
return nil
end
end
table.sort(string_keys)
local map
if #number_keys > 0 then
--
-- If we're here then we have either mixed string/number keys, or numbers inappropriate for a JSON array
-- It's not ideal, but we'll turn the numbers into strings so that we can at least create a JSON object.
--
if self.noKeyConversion then
self:onEncodeError("a table with both numeric and string keys could be an object or array; aborting", etc)
end
--
-- Have to make a shallow copy of the source table so we can remap the numeric keys to be strings
--
map = { }
for key, val in pairs(T) do
map[key] = val
end
table.sort(number_keys)
--
-- Throw numeric keys in there as strings
--
for _, number_key in ipairs(number_keys) do
local string_key = tostring(number_key)
if map[string_key] == nil then
table.insert(string_keys , string_key)
map[string_key] = T[number_key]
else
self:onEncodeError("conflict converting table with mixed-type keys into a JSON object: key " .. number_key .. " exists both as a string and a number.", etc)
end
end
end
return string_keys, nil, map
end
--
-- Encode
--
local encode_value -- must predeclare because it calls itself
function encode_value(self, value, parents, etc, indent) -- non-nil indent means pretty-printing
if value == nil then
return 'null'
elseif type(value) == 'string' then
return json_string_literal(value)
elseif type(value) == 'number' then
if value ~= value then
--
-- NaN (Not a Number).
-- JSON has no NaN, so we have to fudge the best we can. This should really be a package option.
--
return "null"
elseif value >= math.huge then
--
-- Positive infinity. JSON has no INF, so we have to fudge the best we can. This should
-- really be a package option. Note: at least with some implementations, positive infinity
-- is both ">= math.huge" and "<= -math.huge", which makes no sense but that's how it is.
-- Negative infinity is properly "<= -math.huge". So, we must be sure to check the ">="
-- case first.
--
return "1e+9999"
elseif value <= -math.huge then
--
-- Negative infinity.
-- JSON has no INF, so we have to fudge the best we can. This should really be a package option.
--
return "-1e+9999"
else
return tostring(value)
end
elseif type(value) == 'boolean' then
return tostring(value)
elseif type(value) ~= 'table' then
self:onEncodeError("can't convert " .. type(value) .. " to JSON", etc)
else
--
-- A table to be converted to either a JSON object or array.
--
local T = value
if parents[T] then
self:onEncodeError("table " .. tostring(T) .. " is a child of itself", etc)
else
parents[T] = true
end
local result_value
local object_keys, maximum_number_key, map = object_or_array(self, T, etc)
if maximum_number_key then
--
-- An array...
--
local ITEMS = { }
for i = 1, maximum_number_key do
table.insert(ITEMS, encode_value(self, T[i], parents, etc, indent))
end
if indent then
result_value = "[ " .. table.concat(ITEMS, ", ") .. " ]"
else
result_value = "[" .. table.concat(ITEMS, ",") .. "]"
end
elseif object_keys then
--
-- An object
--
local TT = map or T
if indent then
local KEYS = { }
local max_key_length = 0
for _, key in ipairs(object_keys) do
local encoded = encode_value(self, tostring(key), parents, etc, "")
max_key_length = math.max(max_key_length, #encoded)
table.insert(KEYS, encoded)
end
local key_indent = indent .. " "
local subtable_indent = indent .. string.rep(" ", max_key_length + 2 + 4)
local FORMAT = "%s%" .. string.format("%d", max_key_length) .. "s: %s"
local COMBINED_PARTS = { }
for i, key in ipairs(object_keys) do
local encoded_val = encode_value(self, TT[key], parents, etc, subtable_indent)
table.insert(COMBINED_PARTS, string.format(FORMAT, key_indent, KEYS[i], encoded_val))
end
result_value = "{\n" .. table.concat(COMBINED_PARTS, ",\n") .. "\n" .. indent .. "}"
else
local PARTS = { }
for _, key in ipairs(object_keys) do
local encoded_val = encode_value(self, TT[key], parents, etc, indent)
local encoded_key = encode_value(self, tostring(key), parents, etc, indent)
table.insert(PARTS, string.format("%s:%s", encoded_key, encoded_val))
end
result_value = "{" .. table.concat(PARTS, ",") .. "}"
end
else
--
-- An empty array/object... we'll treat it as an array, though it should really be an option
--
result_value = "[]"
end
parents[T] = false
return result_value
end
end
function OBJDEF:encode(value, etc)
if type(self) ~= 'table' or self.__index ~= OBJDEF then
OBJDEF:onEncodeError("JSON:encode must be called in method format", etc)
end
return encode_value(self, value, {}, etc, nil)
end
function OBJDEF:encode_pretty(value, etc)
if type(self) ~= 'table' or self.__index ~= OBJDEF then
OBJDEF:onEncodeError("JSON:encode_pretty must be called in method format", etc)
end
return encode_value(self, value, {}, etc, "")
end
function OBJDEF.__tostring()
return "JSON encode/decode package"
end
OBJDEF.__index = OBJDEF
function OBJDEF:new(args)
local new = { }
if args then
for key, val in pairs(args) do
new[key] = val
end
end
return setmetatable(new, OBJDEF)
end
return OBJDEF:new()
--
-- Version history:
--
-- 20140920.13 Put back (in a way that doesn't cause warnings about unused variables) the author string,
-- so that the source of the package, and its version number, are visible in compiled copies.
--
-- 20140911.12 Minor lua cleanup.
-- Fixed internal reference to 'JSON.noKeyConversion' to reference 'self' instead of 'JSON'.
-- (Thanks to SmugMug's David Parry for these.)
--
-- 20140418.11 JSON nulls embedded within an array were being ignored, such that
-- ["1",null,null,null,null,null,"seven"],
-- would return
-- {1,"seven"}
-- It's now fixed to properly return
-- {1, nil, nil, nil, nil, nil, "seven"}
-- Thanks to "haddock" for catching the error.
--
-- 20140116.10 The user's JSON.assert() wasn't always being used. Thanks to "blue" for the heads up.
--
-- 20131118.9 Update for Lua 5.3... it seems that tostring(2/1) produces "2.0" instead of "2",
-- and this caused some problems.
--
-- 20131031.8 Unified the code for encode() and encode_pretty(); they had been stupidly separate,
-- and had of course diverged (encode_pretty didn't get the fixes that encode got, so
-- sometimes produced incorrect results; thanks to Mattie for the heads up).
--
-- Handle encoding tables with non-positive numeric keys (unlikely, but possible).
--
-- If a table has both numeric and string keys, or its numeric keys are inappropriate
-- (such as being non-positive or infinite), the numeric keys are turned into
-- string keys appropriate for a JSON object. So, as before,
-- JSON:encode({ "one", "two", "three" })
-- produces the array
-- ["one","two","three"]
-- but now something with mixed key types like
-- JSON:encode({ "one", "two", "three", SOMESTRING = "some string" }))
-- instead of throwing an error produces an object:
-- {"1":"one","2":"two","3":"three","SOMESTRING":"some string"}
--
-- To maintain the prior throw-an-error semantics, set
-- JSON.noKeyConversion = true
--
-- 20131004.7 Release under a Creative Commons CC-BY license, which I should have done from day one, sorry.
--
-- 20130120.6 Comment update: added a link to the specific page on my blog where this code can
-- be found, so that folks who come across the code outside of my blog can find updates
-- more easily.
--
-- 20111207.5 Added support for the 'etc' arguments, for better error reporting.
--
-- 20110731.4 More feedback from David Kolf on how to make the tests for Nan/Infinity system independent.
--
-- 20110730.3 Incorporated feedback from David Kolf at http://lua-users.org/wiki/JsonModules:
--
-- * When encoding lua for JSON, Sparse numeric arrays are now handled by
-- spitting out full arrays, such that
-- JSON:encode({"one", "two", [10] = "ten"})
-- returns
-- ["one","two",null,null,null,null,null,null,null,"ten"]
--
-- In 20100810.2 and earlier, only up to the first non-null value would have been retained.
--
-- * When encoding lua for JSON, numeric value NaN gets spit out as null, and infinity as "1+e9999".
-- Version 20100810.2 and earlier created invalid JSON in both cases.
--
-- * Unicode surrogate pairs are now detected when decoding JSON.
--
-- 20100810.2 added some checking to ensure that an invalid Unicode character couldn't leak in to the UTF-8 encoding
--
-- 20100731.1 initial public release
--

@ -1,715 +0,0 @@
-- Module options:
local always_try_using_lpeg = false
local register_global_module_table = false
local global_module_name = 'json'
--[==[
David Kolf's JSON module for Lua 5.1/5.2
Version 2.5
For the documentation see the corresponding readme.txt or visit
<http://dkolf.de/src/dkjson-lua.fsl/>.
You can contact the author by sending an e-mail to 'david' at the
domain 'dkolf.de'.
Copyright (C) 2010-2013 David Heiko Kolf
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
--]==]
-- global dependencies:
local pairs, type, tostring, tonumber, getmetatable, setmetatable, rawset =
pairs, type, tostring, tonumber, getmetatable, setmetatable, rawset
local error, require, pcall, select = error, require, pcall, select
local floor, huge = math.floor, math.huge
local strrep, gsub, strsub, strbyte, strchar, strfind, strlen, strformat =
string.rep, string.gsub, string.sub, string.byte, string.char,
string.find, string.len, string.format
local strmatch = string.match
local concat = table.concat
local json = { version = "dkjson 2.5" }
if register_global_module_table then
_G[global_module_name] = json
end
local _ENV = nil -- blocking globals in Lua 5.2
pcall (function()
-- Enable access to blocked metatables.
-- Don't worry, this module doesn't change anything in them.
local debmeta = require "debug".getmetatable
if debmeta then getmetatable = debmeta end
end)
json.null = setmetatable ({}, {
__tojson = function () return "null" end
})
local function isarray (tbl)
local max, n, arraylen = 0, 0, 0
for k,v in pairs (tbl) do
if k == 'n' and type(v) == 'number' then
arraylen = v
if v > max then
max = v
end
else
if type(k) ~= 'number' or k < 1 or floor(k) ~= k then
return false
end
if k > max then
max = k
end
n = n + 1
end
end
if max > 10 and max > arraylen and max > n * 2 then
print(max.." "..arraylen.." "..n);
return false -- don't create an array with too many holes
end
return true, max
end
local escapecodes = {
["\""] = "\\\"", ["\\"] = "\\\\", ["\b"] = "\\b", ["\f"] = "\\f",
["\n"] = "\\n", ["\r"] = "\\r", ["\t"] = "\\t"
}
local function escapeutf8 (uchar)
local value = escapecodes[uchar]
if value then
return value
end
local a, b, c, d = strbyte (uchar, 1, 4)
a, b, c, d = a or 0, b or 0, c or 0, d or 0
if a <= 0x7f then
value = a
elseif 0xc0 <= a and a <= 0xdf and b >= 0x80 then
value = (a - 0xc0) * 0x40 + b - 0x80
elseif 0xe0 <= a and a <= 0xef and b >= 0x80 and c >= 0x80 then
value = ((a - 0xe0) * 0x40 + b - 0x80) * 0x40 + c - 0x80
elseif 0xf0 <= a and a <= 0xf7 and b >= 0x80 and c >= 0x80 and d >= 0x80 then
value = (((a - 0xf0) * 0x40 + b - 0x80) * 0x40 + c - 0x80) * 0x40 + d - 0x80
else
return ""
end
if value <= 0xffff then
return strformat ("\\u%.4x", value)
elseif value <= 0x10ffff then
-- encode as UTF-16 surrogate pair
value = value - 0x10000
local highsur, lowsur = 0xD800 + floor (value/0x400), 0xDC00 + (value % 0x400)
return strformat ("\\u%.4x\\u%.4x", highsur, lowsur)
else
return ""
end
end
local function fsub (str, pattern, repl)
-- gsub always builds a new string in a buffer, even when no match
-- exists. First using find should be more efficient when most strings
-- don't contain the pattern.
if strfind (str, pattern) then
return gsub (str, pattern, repl)
else
return str
end
end
local function quotestring (value)
-- based on the regexp "escapable" in https://github.com/douglascrockford/JSON-js
value = fsub (value, "[%z\1-\31\"\\\127]", escapeutf8)
if strfind (value, "[\194\216\220\225\226\239]") then
value = fsub (value, "\194[\128-\159\173]", escapeutf8)
value = fsub (value, "\216[\128-\132]", escapeutf8)
value = fsub (value, "\220\143", escapeutf8)
value = fsub (value, "\225\158[\180\181]", escapeutf8)
value = fsub (value, "\226\128[\140-\143\168-\175]", escapeutf8)
value = fsub (value, "\226\129[\160-\175]", escapeutf8)
value = fsub (value, "\239\187\191", escapeutf8)
value = fsub (value, "\239\191[\176-\191]", escapeutf8)
end
return "\"" .. value .. "\""
end
json.quotestring = quotestring
local function replace(str, o, n)
local i, j = strfind (str, o, 1, true)
if i then
return strsub(str, 1, i-1) .. n .. strsub(str, j+1, -1)
else
return str
end
end
-- locale independent num2str and str2num functions
local decpoint, numfilter
local function updatedecpoint ()
decpoint = strmatch(tostring(0.5), "([^05+])</