forked from public/foundryvtt-swade-fr
Fix merges
This commit is contained in:
commit
e3b067c532
18
changelog.md
Normal file
18
changelog.md
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
# 0.21.0.0
|
||||||
|
# 0.21.1.0
|
||||||
|
|
||||||
|
Alignement sur SWADE v1.1.X et traductions de clés manquantes
|
||||||
|
|
||||||
|
# 0.21.0.0
|
||||||
|
|
||||||
|
Alignement sur SWADE v1.1.X
|
||||||
|
|
||||||
|
# 0.20.0.3
|
||||||
|
|
||||||
|
Repository migration
|
||||||
|
|
||||||
|
|
||||||
|
# 0.20.0.1
|
||||||
|
|
||||||
|
Migration of the the module,change of the module owner
|
||||||
|
Corrections sur le manifest
|
846
fr.json
846
fr.json
@ -1,304 +1,546 @@
|
|||||||
{
|
{
|
||||||
"ACTOR.TypeCharacter": "Personnage",
|
"SWADE.CommunityCharSheet": "Ancienne fiche de personnage",
|
||||||
"ACTOR.TypeNpc": "PNJ",
|
"SWADE.CommunityNPCSheet": "Fiche de PNJ communautaire",
|
||||||
"ACTOR.TypeVehicle": "Véhicule",
|
"SWADE.CommunityVicSheet": "Fiche de véhicule communautaire",
|
||||||
"ITEM.TypeAbility": "Capacité",
|
"SWADE.CommunityItemSheet": "Fiche d'objet communautaire",
|
||||||
"ITEM.TypeArmor": "Armure",
|
"SWADE.Expand": "Agrandir",
|
||||||
"ITEM.TypeEdge": "Atout",
|
"SWADE.OfficialSheet": "Fiche officielle Savage Worlds par Pinnacle",
|
||||||
"ITEM.TypeGear": "Équipement",
|
"SWADE.ModHint": "Assurez-vous que votre modificateur inclut un + ou un -",
|
||||||
"ITEM.TypeHindrance": "Handicap",
|
"ACTOR.TypeCharacter": "Personnage",
|
||||||
"ITEM.TypePower": "Pouvoir",
|
"ACTOR.TypeNpc": "PNJ",
|
||||||
"ITEM.TypeShield": "Bouclier",
|
"ACTOR.TypeVehicle": "Véhicule",
|
||||||
"ITEM.TypeSkill": "Compétence",
|
"ITEM.TypeWeapon": "Arme",
|
||||||
"ITEM.TypeWeapon": "Arme",
|
"ITEM.TypeArmor": "Armure",
|
||||||
"SWADE.About": "Description",
|
"ITEM.TypeShield": "Bouclier",
|
||||||
"SWADE.ActionCard": "Carte d'action",
|
"ITEM.TypeGear": "Équipement",
|
||||||
"SWADE.Actions": "Actions",
|
"ITEM.TypeEdge": "Atout",
|
||||||
"SWADE.ActionsEffects": "Actions et Effets",
|
"ITEM.TypeHindrance": "Handicap",
|
||||||
"SWADE.Actors": "Personnages",
|
"ITEM.TypeSkill": "Compétence",
|
||||||
"SWADE.Add": "Ajout",
|
"ITEM.TypePower": "Pouvoir",
|
||||||
"SWADE.AddBenny": "Ajouter un Jeton",
|
"ITEM.TypeAbility": "Capacité",
|
||||||
"SWADE.Addi": "Additionel",
|
"CARD.TypeAdventure":" Cartes d'aventure",
|
||||||
"SWADE.AddStats": "Caractéristiques additionelles",
|
"CARD.TypePoker":" Cartes de Poker",
|
||||||
"SWADE.Adv": "Progressions",
|
"SWADE.Name": "Nom",
|
||||||
"SWADE.Aiming": "Viser",
|
"SWADE.Tough": "Résistance",
|
||||||
"SWADE.All": "Tous",
|
"SWADE.Race": "Espèce",
|
||||||
"SWADE.AllBenniesRefresh": "Réinitialiser tous les Jetons",
|
"SWADE.Pace": "Allure",
|
||||||
"SWADE.AltSkill": "Comp. alternative",
|
"SWADE.Running": "Course",
|
||||||
"SWADE.Ammo": "Munitions",
|
"SWADE.RunningDie": "Dé de course",
|
||||||
"SWADE.AmmoManagement": "Gestion des munitions",
|
"SWADE.RollRun": "Cliquez pour courir",
|
||||||
"SWADE.AmmoManagementDesc": "Quand l'option est activée, et si c'est applicable, les actions soustraient des munitions du chargeur de votre arme. Les cartes d'objet ont aussi un nouveau bouton recharger et vous ne pourrez pas faire d'attaque si vous n'avez pas assez de munitions.",
|
"SWADE.Adv": "Progressions",
|
||||||
"SWADE.AnimalSmarts": "Intellect animal",
|
"SWADE.Rank": "Rang",
|
||||||
"SWADE.Ap": "PA",
|
"SWADE.Inv": "Inventaire",
|
||||||
"SWADE.APLong": "Pénétration d'armure",
|
"SWADE.Summary": "Résumé",
|
||||||
"SWADE.Arcane": "Arcanes",
|
"SWADE.Pow": "Pouvoirs",
|
||||||
"SWADE.ArcBack": "Arcanes",
|
"SWADE.Wildcard": "Joker",
|
||||||
"SWADE.Armor": "Armure",
|
"SWADE.Extra": "Extra",
|
||||||
"SWADE.Armors": "Armures",
|
"SWADE.Bennies": "Jetons",
|
||||||
"SWADE.Arms": "Bras",
|
"SWADE.TraitMod": "Mod. Trait",
|
||||||
"SWADE.AttrAgi": "Agilité",
|
"SWADE.SkillTest": "Jet de compétence",
|
||||||
"SWADE.AttrAgiShort": "Agi",
|
"SWADE.AttributeTest": "Jet d'attribut",
|
||||||
"SWADE.Attributes": "Attributs",
|
"SWADE.Attributes": "Attributs",
|
||||||
"SWADE.AttributeTest": "Jet d'Attribut",
|
"SWADE.Derived": "Caractéristiques dérivées",
|
||||||
"SWADE.AttrSma": "Intellect",
|
"SWADE.AttrAgi": "Agilité",
|
||||||
"SWADE.AttrSmaShort": "Int",
|
"SWADE.AttrSma": "Intellect",
|
||||||
"SWADE.AttrSpr": "Âme",
|
"SWADE.AnimalSmarts": "Intellect animal",
|
||||||
"SWADE.AttrSprShort": "Âme",
|
"SWADE.AttrSpr": "Âme",
|
||||||
"SWADE.AttrStr": "Force",
|
"SWADE.AttrStr": "Force",
|
||||||
"SWADE.AttrStrShort": "For",
|
"SWADE.AttrVig": "Vigueur",
|
||||||
"SWADE.AttrVig": "Vigueur",
|
"SWADE.Tweaks": "Ajustements",
|
||||||
"SWADE.AttrVigShort": "Vig",
|
"SWADE.AttrAgiShort": "Agi",
|
||||||
"SWADE.AutoCalc": "Calculs automatiques",
|
"SWADE.AttrSmaShort": "Int",
|
||||||
"SWADE.AutoCalcParry": "Calculer la Parade automatiquement, bouclier inclus",
|
"SWADE.AttrSprShort": "Âme",
|
||||||
"SWADE.AutoInit": "Initiative automatique",
|
"SWADE.AttrStrShort": "For",
|
||||||
"SWADE.AutoInitDesc": "Pioche automatiquement l'initiative à chaque tour",
|
"SWADE.AttrVigShort": "Vig",
|
||||||
"SWADE.AutoLink": "Lier automatiquement les Jokers",
|
"SWADE.Skills": "Compétences",
|
||||||
"SWADE.AutoLinkDesc": "Les Joker PNJ auront leur pion lié lorsque leur statut sera basculé d'Extra à Joker",
|
"SWADE.Unskilled": "Non entraîné",
|
||||||
"SWADE.AutoReload": "Rechargement auto.",
|
"SWADE.LinkAttr": "Attribut lié",
|
||||||
"SWADE.Bennies": "Jetons",
|
"SWADE.Die": "Dé",
|
||||||
"SWADE.BenniesAddMessage": "a obtenu un nouveau Jeton !",
|
"SWADE.WildDie": "Dé Joker",
|
||||||
"SWADE.BenniesGive": "Donner un Jeton",
|
"SWADE.Modifiers": "Modificateurs",
|
||||||
"SWADE.BenniesGMAddMessage": "Le MJ a obtenu un nouveau Jeton !",
|
"SWADE.Modifier": "Modificateur",
|
||||||
"SWADE.BenniesGMRefreshMessage": "Les Jetons du MJ ont été réinitialisés !",
|
"SWADE.BenniesSpend": "Dépenser un jeton",
|
||||||
"SWADE.BenniesMax": "Réinitialisation des Jetons",
|
"SWADE.BenniesGive": "Donner un jeton",
|
||||||
"SWADE.BenniesRefresh": "Réinitialiser les Jetons",
|
"SWADE.BenniesRefresh": "Réinitialiser les jetons",
|
||||||
"SWADE.BenniesRefreshAllMessage": "Tous les Jetons ont été réinitialisés !",
|
"SWADE.AllBenniesRefresh": "Réinitialiser tous les jetons",
|
||||||
"SWADE.BenniesRefreshMessage": "Les Jetons ont été réinitialisés !",
|
"SWADE.BenniesRefreshMessage": "Les jetons ont été réinitialisés !",
|
||||||
"SWADE.BenniesSpend": "Dépenser un Jeton",
|
"SWADE.BenniesRefreshAllMessage": "Tous les Jjetons ont été réinitialisés !",
|
||||||
"SWADE.BenniesSpendMessage": "dépense un Jeton",
|
"SWADE.BenniesGMRefreshMessage": "Les jetons du MJ ont été réinitialisés !",
|
||||||
"SWADE.Berserk": "Enragé",
|
"SWADE.BenniesAddMessage": "a obtenu un nouveau jeton !",
|
||||||
"SWADE.Biography": "Historique",
|
"SWADE.BenniesGMAddMessage": "Le MJ a obtenu un nouveau jeton !",
|
||||||
"SWADE.BleedingOut": "Hémorragie",
|
"SWADE.BenniesSpendMessage": "dépense un jeton",
|
||||||
"SWADE.Bound": "Immobilisé",
|
"SWADE.BenniesMax": "Réinitialisation des jetons",
|
||||||
"SWADE.Cancel": "Annuler",
|
"SWADE.EditSkill": "Modifier compétence",
|
||||||
"SWADE.CardSound": "Son de pioche de carte",
|
"SWADE.EdEdge": "Modifier Atout",
|
||||||
"SWADE.CardSoundDesc": "Joue un son lorsque l'Initiative est piochée",
|
"SWADE.EdHind": "Modifier Handicap",
|
||||||
"SWADE.Cargo": "Cargaison",
|
"SWADE.Ed": "Modifier",
|
||||||
"SWADE.CargoWeight": "Poids cargaison",
|
"SWADE.Del": "Supprimer",
|
||||||
"SWADE.CarryWeight": "Encombrement",
|
"SWADE.Arcane": "Arcanes",
|
||||||
"SWADE.Class": "Classification",
|
"SWADE.All": "Tous",
|
||||||
"SWADE.CommunityCharSheet": "Ancienne fiche de personnage",
|
"SWADE.HasPowers": "A des pouvoirs",
|
||||||
"SWADE.CommunityItemSheet": "Fiche d'objet communautaire",
|
"SWADE.Weapons": "Armes",
|
||||||
"SWADE.CommunityNPCSheet": "Fiche de PNJ communautaire",
|
"SWADE.MeleeWeapons": "Armes de contact",
|
||||||
"SWADE.CommunityVicSheet": "Fiche de véhicule communautaire",
|
"SWADE.RangedWeapons": "Armes à distance",
|
||||||
"SWADE.Cone": "Gabarit de cône",
|
"SWADE.Range._name": "Portée",
|
||||||
"SWADE.ConfigInit": "Configurer l'Initiative",
|
"SWADE.Armors": "Armures",
|
||||||
"SWADE.Conv": "Conviction",
|
"SWADE.Shields": "Boucliers",
|
||||||
"SWADE.ConvictionActivate": "Fait appel à sa Conviction !",
|
"SWADE.Biography": "Historique",
|
||||||
"SWADE.ConvictionActive": "Conviction active",
|
"SWADE.Shaken": "Secoué",
|
||||||
"SWADE.ConvictionEnd": "vacille dans sa Conviction",
|
"SWADE.Distr": "Distrait",
|
||||||
"SWADE.ConvictionExtend": "Voulez-vous maintenir votre Conviction ?",
|
"SWADE.Vuln": "Vulnérable",
|
||||||
"SWADE.Cover": "Couvert",
|
"SWADE.Stunned": "Sonné",
|
||||||
"SWADE.CoverShield": "Couvert de bouclier",
|
"SWADE.Entangled": "Entravé",
|
||||||
"SWADE.CreateInitChat": "Créer un message dans le chat pour l'Initiative",
|
"SWADE.Bound": "Immobilisé",
|
||||||
"SWADE.Crew": "Équipage requis",
|
"SWADE.Aiming": "Viser",
|
||||||
"SWADE.CurPP": "Pt de pouvoir actuels",
|
"SWADE.Berserk": "Enragé",
|
||||||
"SWADE.Curr": "Actuel",
|
"SWADE.Defending": "Défense totale",
|
||||||
"SWADE.Currency": "Argent",
|
"SWADE.Flying": "En vol",
|
||||||
"SWADE.CurrentBennies": "Jetons actuels",
|
"SWADE.Holding": "En attente",
|
||||||
"SWADE.Defending": "Défense totale",
|
"SWADE.Frightened": "Effrayé",
|
||||||
"SWADE.Del": "Supprimer",
|
"SWADE.Encumbered": "Encombré",
|
||||||
"SWADE.Derived": "Caractéristiques dérivées",
|
"SWADE.Prone": "À terre",
|
||||||
"SWADE.Desc": "Description",
|
"SWADE.BleedingOut": "Hémorragie",
|
||||||
"SWADE.Details": "Détails",
|
"SWADE.Diseased": "Malade",
|
||||||
"SWADE.DiceConf": "Configuration des dés",
|
"SWADE.HeartAttack": "Arrêt cardiaque",
|
||||||
"SWADE.DiceConfDesc": "Configurer les options pour l'intégration SWADE/Dice So Nice",
|
"SWADE.OnFire": "En feu",
|
||||||
"SWADE.DiceConfLabel": "Ouvrir la Configuration des dés",
|
"SWADE.Poisoned": "Empoisonné",
|
||||||
"SWADE.Die": "Dé",
|
"SWADE.Cover.Shield": "Couvert de bouclier",
|
||||||
"SWADE.Diseased": "Malade",
|
"SWADE.CoverShield": "Couvert de bouclier",
|
||||||
"SWADE.Distr": "Distrait",
|
"SWADE.Reach": "Allonge",
|
||||||
"SWADE.Dmg": "Dégâts",
|
"SWADE.Torch": "Torche",
|
||||||
"SWADE.DmgModUni": "Modificateur de dégâts (universel)",
|
"SWADE.Invisible": "Invisible",
|
||||||
"SWADE.DmgOver": "Remplacement des dégâts",
|
"SWADE.Smite": "Frappe",
|
||||||
"SWADE.DSNNone": "- Aucun -",
|
"SWADE.Armor": "Armure",
|
||||||
"SWADE.Dur": "Durée",
|
"SWADE.Protection": "protection",
|
||||||
"SWADE.Ed": "Modifier",
|
"SWADE.Dmg": "Dégâts",
|
||||||
"SWADE.EdEdge": "Modifier Atout",
|
"SWADE.DmgOver": "Remplacement des dégâts",
|
||||||
"SWADE.Edges": "Atouts",
|
"SWADE.Rng": "Portée",
|
||||||
"SWADE.EdgesHindrances": "Atouts et Handicaps",
|
"SWADE.Ap": "PA",
|
||||||
"SWADE.EdHind": "Modifier Handicap",
|
"SWADE.APLong": "Pénétration d'armure",
|
||||||
"SWADE.EditSkill": "Modifier Compétence",
|
"SWADE.RoF": "CdT",
|
||||||
"SWADE.Effects": "Effets actifs",
|
"SWADE.Mag": "Coups",
|
||||||
"SWADE.EnableBennyNotify": "Notifications des Jetons",
|
"SWADE.Parry": "Parade",
|
||||||
"SWADE.EnableBennyNotifyDesc": "Affiche des messages dans le chat lorsque les Jetons sont modifiés.",
|
"SWADE.Cover._name": "Couvert",
|
||||||
"SWADE.EnableConv": "Activer la Conviction",
|
"SWADE.Couvert._name": "Couvert",
|
||||||
"SWADE.EnableConvDesc": "Active la règle d'univers Conviction",
|
"SWADE.Notes": "Notes",
|
||||||
"SWADE.Enabled": "Activé",
|
"SWADE.ActionsEffects": "Actions et Effets",
|
||||||
"SWADE.EnableWoundPace": "Ajuster l'Allure avec les Blessures",
|
"SWADE.Actions": "Actions",
|
||||||
"SWADE.EnableWoundPaceDesc": "Quand l'option est activée, l'Allure est automatiquement affectée par les Blessures",
|
"SWADE.DmgModUni": "Modificateur de dégâts (universel)",
|
||||||
"SWADE.Encumbered": "Encombré",
|
"SWADE.SkillModUni": "Modificateur de comp. (universel)",
|
||||||
"SWADE.Entangled": "Entravé",
|
"SWADE.ShotsUsed": "Mun. utilisées",
|
||||||
"SWADE.Eqd": "Éqpé",
|
"SWADE.NaturalArmor": "Armure naturelle",
|
||||||
"SWADE.Equippable": "Équipable",
|
"SWADE.HitLocations": "Localisation",
|
||||||
"SWADE.Equipped": "Équipé",
|
"SWADE.Head": "Tête",
|
||||||
"SWADE.Expand": "Agrandir",
|
"SWADE.Torso": "Torse",
|
||||||
"SWADE.Extra": "Extra",
|
"SWADE.Arms": "Bras",
|
||||||
"SWADE.Fatigue": "Fatigue",
|
"SWADE.Legs": "Jambes",
|
||||||
"SWADE.FatigueMax": "Fatigue max.",
|
"SWADE.MinStrLong": "Force minimale",
|
||||||
"SWADE.Flying": "En Vol",
|
"SWADE.MinStr": "Force min.",
|
||||||
"SWADE.Formula": "Formule",
|
"SWADE.MinStrShort": "For min.",
|
||||||
"SWADE.FreeReroll": "Relance gratuite",
|
"SWADE.Desc": "Description",
|
||||||
"SWADE.Frightened": "Effrayé",
|
"SWADE.Special": "Capacités spéciales",
|
||||||
"SWADE.General": "Général",
|
"SWADE.Details": "Détails",
|
||||||
"SWADE.GM": "Meneur de Jeu",
|
"SWADE.Equippable": "Équipable",
|
||||||
"SWADE.GmBennies": "Jetons du MJ",
|
"SWADE.Misc": "Divers",
|
||||||
"SWADE.GmBenniesDesc": "Détermine combien de Jetons le MJ reçoit après une réinitialisation",
|
"SWADE.QuickAccess": "Accès rapide",
|
||||||
"SWADE.GrantsPowers": "Accorde des pouvoirs",
|
"SWADE.Effects": "Effets actifs",
|
||||||
"SWADE.GroupRoll": "Jet de groupe",
|
"SWADE.Hindrances": "Handicaps",
|
||||||
"SWADE.Handling": "Manœuvrabilité",
|
"SWADE.MajHind": "Handicap majeur",
|
||||||
"SWADE.HasMaxValue": "A une valeur max.",
|
"SWADE.Major": "(majeur)",
|
||||||
"SWADE.HasPowers": "A des pouvoirs",
|
"SWADE.Minor": "(mineur)",
|
||||||
"SWADE.Head": "Tête",
|
"SWADE.Edges": "Atouts",
|
||||||
"SWADE.HeartAttack": "Arrêt cardiaque",
|
"SWADE.ArcBack": "Arcanes",
|
||||||
"SWADE.Hesitant": "Hésitant",
|
"SWADE.Req": "Prérequis",
|
||||||
"SWADE.HideNpcItemChatCards": "Cacher les cartes du chat d'objets des PNJ",
|
"SWADE.Conv": "Conviction",
|
||||||
"SWADE.HideNpcItemChatCardsDesc": "Quand l'option est activée, les cartes du chat d'objets des PNJ sont automatiquement envoyées en message privé à tous les Meneurs de Jeu au lieu d'être envoyées en chat public",
|
"SWADE.UseConv": "Fait appel à sa conviction !",
|
||||||
"SWADE.HideWC": "Cache le Joker des PNJ",
|
"SWADE.Hesitant": "Hésitant",
|
||||||
"SWADE.HideWCDesc": "Ne montre pas le signe Joker aux joueurs pour les PNJ",
|
"SWADE.LevelHeaded": "Tête froide",
|
||||||
"SWADE.Hindrances": "Handicaps",
|
"SWADE.ImprovedLevelHeaded": "Sang-froid",
|
||||||
"SWADE.HitLocations": "Localisation",
|
"SWADE.AutoCalc": "Calculs automatiques",
|
||||||
"SWADE.Holding": "En attente",
|
"SWADE.InclArmor": "Calcule automatiquement la résistance, armure incluse",
|
||||||
"SWADE.IgnWounds": "Ignorer les Blessures",
|
"SWADE.Label": "Label",
|
||||||
"SWADE.ImprovedLevelHeaded": "Sang-froid",
|
"SWADE.HasMaxValue": "A une valeur max.",
|
||||||
"SWADE.Incap": "Incapacité",
|
"SWADE.Enabled": "Activé",
|
||||||
"SWADE.InclArmor": "Calcule automatiquement la Résistance, armure incluse",
|
"SWADE.Currency": "Argent",
|
||||||
"SWADE.Init": "Initiative",
|
"SWADE.CarryWeight": "Encombrement",
|
||||||
"SWADE.InitDraw": "pioche son Initiative !",
|
"SWADE.Eqd": "Éqpé",
|
||||||
"SWADE.Inv": "Inventaire",
|
"SWADE.Equipped": "Équipé",
|
||||||
"SWADE.Invisible": "Invisible",
|
"SWADE.Unequipped": "Non équipé",
|
||||||
"SWADE.Item": "Objet",
|
"SWADE.Quantity": "Quantité",
|
||||||
"SWADE.Items": "Objets",
|
"SWADE.Weight": "Poids",
|
||||||
"SWADE.JokersWild": "Un joker, c'est fou !",
|
"SWADE.Price": "Prix",
|
||||||
"SWADE.JokersWildDesc": "Donner un Jeton à tous les PJ lorsque l'un d'entre eux tire un joker",
|
"SWADE.PP": "Points de pouvoir",
|
||||||
"SWADE.Label": "Label",
|
"SWADE.PPShort": "Pt de pouvoir",
|
||||||
"SWADE.LBT": "Grand gabarit",
|
"SWADE.CurPP": "Pt de pouvoir actuels",
|
||||||
"SWADE.Legs": "Jambes",
|
"SWADE.MaxPP": "Pt de pouvoir max.",
|
||||||
"SWADE.LevelHeaded": "Tête froide",
|
"SWADE.Dur": "Durée",
|
||||||
"SWADE.LinkAttr": "Attribut lié",
|
"SWADE.Trap": "Aspect",
|
||||||
"SWADE.Mag": "Coups",
|
"SWADE.Wound": "Blessure",
|
||||||
"SWADE.MajHind": "Handicap Majeur",
|
"SWADE.Wounds": "Blessures",
|
||||||
"SWADE.Major": "(Majeur)",
|
"SWADE.WoundsMax": "Blessures max.",
|
||||||
"SWADE.ManCheck": "Jet de Manœuvre",
|
"SWADE.Fatigue": "Fatigue",
|
||||||
"SWADE.Max": "Max.",
|
"SWADE.FatigueMax": "Fatigue max.",
|
||||||
"SWADE.MaxCargo": "Encombrement max. cargaison",
|
"SWADE.Incap": "Incapacité",
|
||||||
"SWADE.MaxMods": "Mods Maximums",
|
"SWADE.Init": "Initiative",
|
||||||
"SWADE.MaxPP": "Pt de pouvoir max.",
|
"SWADE.InitDraw": "pioche son initiative !",
|
||||||
"SWADE.MBT": "Gabarit moyen",
|
"SWADE.JokersWild": "Un joker, c'est fou !",
|
||||||
"SWADE.MeleeWeapons": "Armes de contact",
|
"SWADE.General": "Général",
|
||||||
"SWADE.Minor": "(Mineur)",
|
"SWADE.Addi": "Additionel",
|
||||||
"SWADE.MinStr": "Force min.",
|
"SWADE.Status": "Statut",
|
||||||
"SWADE.MinStrLong": "Force minimale",
|
"SWADE.Handling": "Manœuvrabilité",
|
||||||
"SWADE.MinStrShort": "For min.",
|
"SWADE.Topspeed": "Vitesse max",
|
||||||
"SWADE.Misc": "Divers",
|
"SWADE.OutOfControl": "Hors de contrôle",
|
||||||
"SWADE.Mod": "Modificateur",
|
"SWADE.Wrecked": "Épave",
|
||||||
"SWADE.ModHint": "Assurez-vous que votre modificateur inclut un + ou un -",
|
"SWADE.Item": "Objet",
|
||||||
"SWADE.Mods": "Mods",
|
"SWADE.Cargo": "Cargaison",
|
||||||
"SWADE.ModSlots": "Emplacements de Mods",
|
"SWADE.MaxCargo": "Encombrement max. cargaison",
|
||||||
"SWADE.Name": "Nom",
|
"SWADE.CargoWeight": "Poids cargaison",
|
||||||
"SWADE.NaturalArmor": "Armure naturelle",
|
"SWADE.Mods": "Mods",
|
||||||
"SWADE.NoAmmoSet": "Il n'y a pas de munitions affectées",
|
"SWADE.ModSlots": "Emplacements de Mods",
|
||||||
"SWADE.NoBennies": "Vous n'avez plus de Jetons !",
|
"SWADE.MaxMods": "Mods Maximums",
|
||||||
"SWADE.NoCardsLeft": "Il n'y a plus assez de cartes dans le paquet !",
|
"SWADE.Operator": "Conducteur",
|
||||||
"SWADE.NotEnoughAmmo": "Vous n'avez pas assez de munitions pour effectuer cette action !",
|
"SWADE.ManCheck": "Jet de manœuvre",
|
||||||
"SWADE.NotEnoughAmmoToReload": "Il n'y a pas assez de munitions pour une recharge complète",
|
"SWADE.AltSkill": "Comp. alternative",
|
||||||
"SWADE.Notes": "Notes",
|
"SWADE.Class": "Classification",
|
||||||
"SWADE.NPCAmmoFromInventory": "Les PNJ utilisent les munitions de l'inventaire",
|
"SWADE.Vehicular": "Arme de véhicule",
|
||||||
"SWADE.OfficialSheet": "Fiche officielle Savage Worlds par Pinnacle",
|
"SWADE.VehicleMod": "Mod de véhicule",
|
||||||
"SWADE.Ok": "Ok",
|
"SWADE.OpSkill": "Compétence de manœuvre",
|
||||||
"SWADE.OldCard": "Ancienne carte",
|
"SWADE.CardSound": "Son de pioche de carte",
|
||||||
"SWADE.OnFire": "En feu",
|
"SWADE.CardSoundDesc": "Joue un son lorsque l'initiative est piochée",
|
||||||
"SWADE.Operator": "Conducteur",
|
"SWADE.AutoInit": "Initiative automatique",
|
||||||
"SWADE.OpSkill": "Compétence de manœuvre",
|
"SWADE.AutoInitDesc": "Pioche automatiquement l'initiative à chaque tour",
|
||||||
"SWADE.OutOfControl": "Hors de contrôle",
|
"SWADE.CreateInitChat": "Créer un message dans le chat pour l'initiative",
|
||||||
"SWADE.Pace": "Allure",
|
"SWADE.HideWC": "Cache le Joker des PNJ",
|
||||||
"SWADE.Parry": "Parade",
|
"SWADE.HideWCDesc": "Ne montre pas le signe Joker aux joueurs pour les PNJ",
|
||||||
"SWADE.ParryBase": "Compétence liée à la Parade",
|
"SWADE.EnableConv": "Activer la conviction",
|
||||||
"SWADE.ParryBaseDesc": "Le nom de la Compétence qui sera utilisée pour calculer la Parade du personnage",
|
"SWADE.EnableConvDesc": "Active la règle d'univers conviction",
|
||||||
"SWADE.Passengers": "Passagers",
|
"SWADE.EnableWoundPace": "Ajuster l'allure avec les blessures",
|
||||||
"SWADE.PCAmmoFromInventory": "Les PJ utilisent les munitions de l'inventaire",
|
"SWADE.EnableWoundPaceDesc": "Quand l'option est activée, l'allure est automatiquement affectée par les blessures",
|
||||||
"SWADE.PCAmmoFromInventoryDesc": "Quand l'option est activée, il est possible de marquer un objet « Équipement » comme munitions. Il sera utilisé pour recharger l'arme.",
|
"SWADE.AutoLink": "Lier automatiquement les jokers",
|
||||||
"SWADE.PickACard": "Piocher une carte",
|
"SWADE.AutoLinkDesc": "Les Jokers PNJ auront leur pion lié lorsque leur statut sera basculé d'Extra à Joker",
|
||||||
"SWADE.Poisoned": "Empoisonné",
|
"SWADE.GmBennies": "Jetons du MJ",
|
||||||
"SWADE.Pow": "Pouvoirs",
|
"SWADE.GmBenniesDesc": "Détermine combien de jetons le MJ reçoit après une réinitialisation",
|
||||||
"SWADE.PP": "Points de pouvoir",
|
"SWADE.EnableBennyNotify": "Notifications des jetons",
|
||||||
"SWADE.PPShort": "Pt de pouvoir",
|
"SWADE.EnableBennyNotifyDesc": "Affiche des messages dans le chat lorsque les jetons sont modifiés.",
|
||||||
"SWADE.Price": "Prix",
|
"SWADE.VehicleMods": "Mods du véhicules",
|
||||||
"SWADE.Prone": "À terre",
|
"SWADE.VehicleModsDesc": "Le véhicule a des emplacements de mods",
|
||||||
"SWADE.Protection": "protection",
|
"SWADE.VehicleEdges": "Atouts du véhicule",
|
||||||
"SWADE.Quantity": "Quantité",
|
"SWADE.VehicleEdgesDesc": "Le véhicule utilise des Atouts et des Handicaps",
|
||||||
"SWADE.QuickAccess": "Accès rapide",
|
"SWADE.ShowBennyAnimation": "Montrer l'animation du Jeton",
|
||||||
"SWADE.Race": "Espèce",
|
"SWADE.ShowBennyAnimationDesc": "Joue une animation en dépensant un jeton. Seulement disponible si Dice So Nice! est installé",
|
||||||
"SWADE.RacialAbilities": "Capacités innées",
|
"SWADE.WildDiePreset": "Thème du dé joker",
|
||||||
"SWADE.RangedWeapons": "Armes à distance",
|
"SWADE.WildDiePresetDesc": "Sélectionnez un thème DSN pour votre dé joker. Sélectionnez « Personnalisé » si vous voulez créer le vôtre ou « Aucun » si vous ne voulez pas que votre dé Joker soit différent. Gardez à l'esprit que pour le moment, il n'y a que vous qui puissiez voir votre dé Joker personnalisé. Les autres joueurs le verrons différemment.",
|
||||||
"SWADE.Rank": "Rang",
|
"SWADE.AmmoManagement": "Gestion des munitions",
|
||||||
"SWADE.Reach": "Allonge",
|
"SWADE.AmmoManagementDesc": "Quand l'option est activée, et si c'est applicable, les actions soustraient des munitions du chargeur de votre arme. Les cartes d'objet ont aussi un nouveau bouton recharger et vous ne pourrez pas faire d'attaque si vous n'avez pas assez de munitions.",
|
||||||
"SWADE.Redraw": "Re-piocher",
|
"SWADE.PCAmmoFromInventory": "Les PJ utilisent les munitions de l'inventaire",
|
||||||
"SWADE.Refresh": "Rafraichir cette carte",
|
"SWADE.PCAmmoFromInventoryDesc": "Quand l'option est activée, il est possible de marquer un objet « Équipement » comme munitions. Il sera utilisé pour recharger l'arme.",
|
||||||
"SWADE.Reload": "Recharger",
|
"SWADE.NPCAmmoFromInventory": "Les PNJ utilisent les munitions de l'inventaire",
|
||||||
"SWADE.ReloadSuccess": "L'arme a été rechargée avec succès",
|
"SWADE.VehicleAmmoFromInventory": "Les véhicules utilisent les munitions de l'inventaire",
|
||||||
"SWADE.ReloadUnneeded": "Cette arme est déjà complètement chargée",
|
"SWADE.SettingConf": "Configuration des règles",
|
||||||
"SWADE.Req": "Prérequis",
|
"SWADE.SettingConfLabel": "Ouvrir la configuration des règles",
|
||||||
"SWADE.RerollWithBenny": "Relancer avec un Jeton",
|
"SWADE.SettingConfDesc": "Ajustez le système pour qu'il s'adapte à l'univers auquel vous jouez",
|
||||||
"SWADE.Rng": "Portée",
|
"SWADE.DiceConf": "Configuration des dés",
|
||||||
"SWADE.RoF": "CdT",
|
"SWADE.DiceConfDesc": "Configurer les options pour l'intégration SWADE/Dice So Nice",
|
||||||
"SWADE.Roll": "Jeter",
|
"SWADE.DiceConfLabel": "Ouvrir la Configuration des dés",
|
||||||
"SWADE.RollExample": "ex. +1d6x= or -2",
|
"SWADE.Formula": "Formule",
|
||||||
"SWADE.RollMode": "Mode de jet",
|
"SWADE.SitMod": "Modificateur de situation",
|
||||||
"SWADE.RollRaise": "Avec Prouesse",
|
"SWADE.RollMode": "Mode de jet",
|
||||||
"SWADE.RollRun": "Cliquez pour courir",
|
"SWADE.RollExample": "ex. +1d6x= ou -2",
|
||||||
"SWADE.Running": "Course",
|
"SWADE.Roll": "Jeter",
|
||||||
"SWADE.RunningDie": "Dé de Course",
|
"SWADE.RollRaise": "Avec Prouesse",
|
||||||
"SWADE.SBT": "Petit gabarit",
|
"SWADE.GroupRoll": "Jet de groupe",
|
||||||
"SWADE.Scale": "Échelle",
|
"SWADE.Ok": "Ok",
|
||||||
"SWADE.SettingConf": "Configuration des règles",
|
"SWADE.Cancel": "Annuler",
|
||||||
"SWADE.SettingConfDesc": "Ajustez le système pour qu'il s'adapte à l'univers auquel vous jouez",
|
"SWADE.Redraw": "Re-piocher",
|
||||||
"SWADE.SettingConfLabel": "Ouvrir la Configuration des règles",
|
"SWADE.Add": "Ajout",
|
||||||
"SWADE.Shaken": "Secoué",
|
"SWADE.ConfigInit": "Configurer l'initiative",
|
||||||
"SWADE.Shields": "Boucliers",
|
"SWADE.IgnWounds": "Ignorer les blessures",
|
||||||
"SWADE.ShotsUsed": "Mun. utilisées",
|
"SWADE.Size": "Taille",
|
||||||
"SWADE.ShowBennyAnimation": "Montrer l'animation du Jeton",
|
"SWADE.Scale": "Échelle",
|
||||||
"SWADE.ShowBennyAnimationDesc": "Joue une animation en dépensant un jeton. Seulement disponible si Dice So Nice! est installé",
|
"SWADE.PickACard": "Piocher une carte",
|
||||||
"SWADE.SitMod": "Modificateur de situation",
|
"SWADE.NoCardsLeft": "Il n'y a plus assez de cartes dans le paquet !",
|
||||||
"SWADE.Size": "Taille",
|
"SWADE.OldCard": "Ancienne carte",
|
||||||
"SWADE.SkillModUni": "Modificateur de comp. (universel)",
|
"SWADE.ActionCard": "Carte d'action",
|
||||||
"SWADE.Skills": "Compétences",
|
"SWADE.ConvictionActive": "Conviction active",
|
||||||
"SWADE.SkillTest": "Jet de Compétence",
|
"SWADE ConvictionActivate": "Fait appel à sa conviction !",
|
||||||
"SWADE.Smite": "Frappe",
|
"SWADE.ConvictionExtend": "Voulez-vous maintenir votre conviction ?",
|
||||||
"SWADE.Special": "Capacités spéciales",
|
"SWADE.ConvictionEnd": "vacille dans sa conviction",
|
||||||
"SWADE.SpecialAbilities": "Capacités spéciales",
|
"SWADE.NoBennies": "Vous n'avez plus de jetons !",
|
||||||
"SWADE.SpecialAbility": "Capacité spéciale",
|
"SWADE.SBT": "Petit gabarit",
|
||||||
"SWADE.Status": "Statut",
|
"SWADE.MBT": "Gabarit moyen",
|
||||||
"SWADE.Stunned": "Sonné",
|
"SWADE.LBT": "Grand gabarit",
|
||||||
"SWADE.Subtype": "Sous-type",
|
"SWADE.Cone": "Gabarit de cône",
|
||||||
"SWADE.Summary": "Résumé",
|
"SWADE.GM": "Meneur de Jeu",
|
||||||
"SWADE.Topspeed": "Vitesse Max",
|
"SWADE.Vehicles": "Véhicules",
|
||||||
"SWADE.Torch": "Torche",
|
"SWADE.AddStats": "Caractéristiques additionelles",
|
||||||
"SWADE.Torso": "Torse",
|
"SWADE.Actors": "Personnages",
|
||||||
"SWADE.Tough": "Résistance",
|
"SWADE.Items": "Objets",
|
||||||
"SWADE.TraitMod": "Mod. Trait",
|
"SWADE.Max": "Max.",
|
||||||
"SWADE.Trap": "Aspect",
|
"SWADE.Curr": "Actuel",
|
||||||
"SWADE.Trapping": "Aspects",
|
"SWADE.DSNNone": "- Aucun -",
|
||||||
"SWADE.Tweaks": "Ajustements",
|
"SWADE.Reload": "Recharger",
|
||||||
"SWADE.Unequipped": "Non équipé",
|
"SWADE.Refresh": "Rafraichir cette carte",
|
||||||
"SWADE.Unskilled": "Non entraîné",
|
"SWADE.Ammo": "Munitions",
|
||||||
"SWADE.UseConv": "Fait appel à sa Conviction !",
|
"SWADE.ReloadUnneeded": "Cette arme est déjà complètement chargée",
|
||||||
"SWADE.VehicleAmmoFromInventory": "Les véhicules utilisent les munitions de l'inventaire",
|
"SWADE.ReloadSuccess": "L'arme a été rechargée avec succès",
|
||||||
"SWADE.VehicleEdges": "Atouts du véhicule",
|
"SWADE.NotEnoughAmmo": "Vous n'avez pas assez de munitions pour effectuer cette action !",
|
||||||
"SWADE.VehicleEdgesDesc": "Le véhicule utilise des Atouts et des Handicaps",
|
"SWADE.NotEnoughAmmoToReload": "Il n'y a pas assez de munitions pour une recharge complète",
|
||||||
"SWADE.VehicleMod": "Mod de véhicule",
|
"SWADE.AutoReload": "Rechargement auto.",
|
||||||
"SWADE.VehicleMods": "Mods du véhicules",
|
"SWADE.NoAmmoSet": "Il n'y a pas de munitions affectées",
|
||||||
"SWADE.VehicleModsDesc": "Le véhicule a des emplacements de mods",
|
"SWADE.Trapping": "Aspects",
|
||||||
"SWADE.Vehicles": "Véhicules",
|
"SWADE.AddBenny": "Ajouter un Jjton",
|
||||||
"SWADE.Vehicular": "Arme de véhicule",
|
"SWADE.CurrentBennies": "Jetons actuels",
|
||||||
"SWADE.Vuln": "Vulnérable",
|
"SWADE.RerollWithBenny": "Relancer avec un jeton",
|
||||||
"SWADE.Weapons": "Armes",
|
"SWADE.FreeReroll": "Relance gratuite",
|
||||||
"SWADE.Weight": "Poids",
|
"SWADE.HideNpcItemChatCards": "Cacher les cartes du chat d'objets des PNJ",
|
||||||
"SWADE.WildCard": "Joker",
|
"SWADE.HideNpcItemChatCardsDesc": "Quand l'option est activée, les cartes du chat d'objets des PNJ sont automatiquement envoyées en message privé à tous les Meneurs de Jeu au lieu d'être envoyées en chat public",
|
||||||
"SWADE.WildDie": "Dé Joker",
|
"SWADE.JokersWildDesc": "Donner un jeton à tous les PJ lorsque l'un d'entre eux tire un joker",
|
||||||
"SWADE.WildDiePreset": "Thème du dé Joker",
|
"SWADE.ParryBase": "Compétence liée à la parade",
|
||||||
"SWADE.WildDiePresetDesc": "Sélectionnez un thème DSN pour votre dé Joker. Sélectionnez « Personnalisé » si vous voulez créer le vôtre ou « Aucun » si vous ne voulez pas que votre dé Joker soit différent. Gardez à l'esprit que pour le moment, il n'y a que vous qui puissiez voir votre dé Joker personnalisé. Les autres joueurs le verrons différemment.",
|
"SWADE.ParryBaseDesc": "Le nom de la Compétence qui sera utilisée pour calculer la parade du personnage",
|
||||||
"SWADE.Wound": "Blessure",
|
"SWADE.AutoCalcParry": "Calculer la parade automatiquement, bouclier inclus",
|
||||||
"SWADE.Wounds": "Blessures",
|
"SWADE.Subtype": "Sous-type",
|
||||||
"SWADE.WoundsMax": "Blessures max.",
|
"SWADE.SpecialAbility": "Capacité spéciale",
|
||||||
"SWADE.Wrecked": "Épave"
|
"SWADE.SpecialAbilities": "Capacités spéciales",
|
||||||
|
"SWADE.RacialAbilities": "Capacités innées",
|
||||||
|
"SWADE.About": "Description",
|
||||||
|
"SWADE.EdgesHindrances": "Atouts et Handicaps",
|
||||||
|
"SWADE.GrantsPowers": "Accorde des pouvoirs",
|
||||||
|
"SWADE.Crew": "Équipage requis",
|
||||||
|
"SWADE.Passengers": "Passagers",
|
||||||
|
|
||||||
|
"SWADE.ActAfterCurrentCombatant":"Agir après le combattant actuel",
|
||||||
|
"SWADE.ActNow": "Agir maintenant",
|
||||||
|
"SWADE.ActionDeckPresetDark":"Cartes d'action (Sombre)",
|
||||||
|
"SWADE.ActionDeckPresetLight":" Action Deck (Light)",
|
||||||
|
"SWADE.ActionDeckReset":" Reset Action Deck",
|
||||||
|
"SWADE.ActionDeckResetNotification":"Réinitialise les cartes d'action",
|
||||||
|
"SWADE.ActivateArcaneDevice":"Activer l'objet",
|
||||||
|
"SWADE.AddTokenFollowers":"Ajouter les tokens sélectionnés comme suivants",
|
||||||
|
"SWADE.AnimalSmartsMarker":"A",
|
||||||
|
"SWADE.ArcaneDevice":"Objet Arcanique",
|
||||||
|
"SWADE.ArcaneSkill":"Compétence d'arcane",
|
||||||
|
"SWADE.Archetype":"Archétype",
|
||||||
|
"SWADE.ArchetypeAbilities":"Capacités d'archetype",
|
||||||
|
"SWADE.ButtonReset":"Ré-initialisation",
|
||||||
|
"SWADE.ButtonSubmit":"Soumettre",
|
||||||
|
"SWADE.ConvictionActivate":"Faire appel à leur convictin!",
|
||||||
|
"SWADE.CoreSkill":"Compétence de base",
|
||||||
|
"SWADE.CoreSkills":"Compétences de base",
|
||||||
|
"SWADE.CoreSkillsDesc":" >-",
|
||||||
|
"SWADE.DrawInit":"Lancer l'initiative",
|
||||||
|
"SWADE.Follow":"Suivre {name}",
|
||||||
|
"SWADE.GroupByName":"Grouper par nom",
|
||||||
|
"SWADE.Hold":"Conserver",
|
||||||
|
"SWADE.LoseTurn":"Toggle Lose Turn",
|
||||||
|
"SWADE.MakeGroupLeader":"Faire un Chef de groupe",
|
||||||
|
"SWADE.PPCost":"Coût en PP",
|
||||||
|
"SWADE.RemoveGroupLeader":"Supprimer le chef de groupe",
|
||||||
|
"SWADE.SelectColor":"Selectionner une couleur",
|
||||||
|
"SWADE.SetGroupColor":"Choisir une couleur de groupe",
|
||||||
|
"SWADE.Unfollow":"Arrêter de suivre {name}",
|
||||||
|
"SWADE.WeaponsAndArmor":"Armes & Armuress",
|
||||||
|
"SWADE.WildCard":"Joker",
|
||||||
|
|
||||||
|
"SWADE.String": "Texte",
|
||||||
|
"SWADE.Number": "Nombre",
|
||||||
|
"SWADE.Checkbox": "Checkbox",
|
||||||
|
"SWADE.Ace": "As",
|
||||||
|
"SWADE.NoPowerPoints": "Pas de Points de Pouvoir",
|
||||||
|
"SWADE.NoPowerPointsDesc": "Lorsque activé, cette option cache toutes les interactions avec les Points de Pouvoir",
|
||||||
|
"SWADE.WealthType": "Type de Richesse",
|
||||||
|
"SWADE.WealthDie": "Dé de Richesse",
|
||||||
|
"SWADE.WealthTypeDesc": "Choississez comment suivre la richesse des personnages et leur argent",
|
||||||
|
"SWADE.CurrencyName": "Nom de monnaie",
|
||||||
|
"SWADE.CurrencyNameDesc": "Nommez la monnaie utilisée",
|
||||||
|
"SWADE.TraitRolls": "Jets de Trait",
|
||||||
|
"SWADE.Trait": "Trait",
|
||||||
|
"SWADE.AltTrait": "Trait Alternatif",
|
||||||
|
"SWADE.ClickSuggestions": "Cliquez pour les suggestions",
|
||||||
|
"SWADE.Quick": "Rapide",
|
||||||
|
"SWADE.BonusDamage": "Bonus aux dégâts",
|
||||||
|
"SWADE.CoreSkillsPack": "Compendium des Compatences de base",
|
||||||
|
"SWADE.CoreSkillsPackDesc": "Choisissez le compendium d'ou proviennent les compétences de base",
|
||||||
|
"SWADE.Joker": "Joker",
|
||||||
|
"SWADE.Subtract": "Soustraire",
|
||||||
|
"SWADE.DmgRolls": "Jets de Dégats",
|
||||||
|
"SWADE.SubtractPPDesc": "Soustraire le cout en PP du total disponible",
|
||||||
|
"SWADE.AddPPDesc": "Ajouter le cout en PP au total disponible",
|
||||||
|
"SWADE.RightClickZoom": "Click droit pour zoomer",
|
||||||
|
"SWADE.SysMigrationWarning": "Votre installation de SWADE est ancienne et ne peut pas être migrée à la nouvelle version. La migration va être tentée, mais des erreurs peuvent se produire",
|
||||||
|
"SWADE.SomethingWrongWithCardComp": "Une erreur s'est produite avec le Compendium de Cartes, positionnement sur le réglage par défaut",
|
||||||
|
"SWADE.DeckShuffled": "Le paquet de cartes a été automatiquement mélangé",
|
||||||
|
"SWADE.BasePace": "Allure de base",
|
||||||
|
"SWADE.WarningPackLocked": "Vous ne pouvez pas éditer un Compendium verouillé. Dévérouillez le d'abord.",
|
||||||
|
"SWADE.ActionCardEditor": "Editeur de cartes d'action",
|
||||||
|
"SWADE.CardFace": "Figure",
|
||||||
|
"SWADE.CardValue": "Valeur",
|
||||||
|
"SWADE.CardSuit": "Suite",
|
||||||
|
"SWADE.IsJoker": "Est un Joker",
|
||||||
|
"SWADE.OpenACEditor": "Ouvert dans l'Editeur de cartes d'action",
|
||||||
|
"SWADE.Yes": "Oui",
|
||||||
|
"SWADE.No": "Non",
|
||||||
|
"SWADE.ShowCharacterSummary": "Afficher le résumé du personnage",
|
||||||
|
"SWADE.CharacterSummary": "Résumé de personnage",
|
||||||
|
"SWADE.CopyHtml": "Copier le HTML",
|
||||||
|
"SWADE.CopyMarkdown": "Copier le Markdown",
|
||||||
|
"SWADE.InitCardDeck": "Jeu de carte pour l'initiative",
|
||||||
|
"SWADE.Imperial": "Imperiale",
|
||||||
|
"SWADE.Metric": "Métrique",
|
||||||
|
"SWADE.WeightUnitLabel": "Unite de poids",
|
||||||
|
"SWADE.WeightUnitDesc": "Indique si les poids sont mesurés en livres ou en kilogrammes. Changer ce paramètre ne changera PAS le poids des items, uniquement le calcul de l'encombrement",
|
||||||
|
"SWADE.UseAttributeShorts": "Utiliser des noms d'attributs courts",
|
||||||
|
"SWADE.UseAttributeShortsDesc": "Activez cette option si vous voulez des noms d'attributs courts sur les fiches de PJs et PNJs (ie Agi au lieu de Agilité ...)",
|
||||||
|
"SWADE.BennyImageSheet": "Jeton",
|
||||||
|
"SWADE.BennyImageSheetDesc": "Sélectionnez l'image voulue pour les jetons sur la fiche de Personnage",
|
||||||
|
"SWADE.Benny3DFront": "Texture de face",
|
||||||
|
"SWADE.Benny3DFrontDesc": "Texture de face des jetons 3D",
|
||||||
|
"SWADE.Benny3DBack": "Texture arrière",
|
||||||
|
"SWADE.Benny3DBackDesc": "Texture arrière des jetons 3D",
|
||||||
|
"SWADE.ChangeBennyWarning": "Changer ces paramètres nécessite un rechargement de la page !",
|
||||||
|
"SWADE.3DBennies": "Jetons 3D",
|
||||||
|
"SWADE.HardChoices": "Choix Cornéliens",
|
||||||
|
"SWADE.HardChoicesDesc": "Cocher cette option activera les règles de Choix Cornéliens",
|
||||||
|
"SWADE.WealthSelectionNoneOther": "Aucun/Autre",
|
||||||
|
"SWADE.Benny3DFrontBump": "Relief texture de face",
|
||||||
|
"SWADE.Benny3DBackBump": "Relief texture arrière",
|
||||||
|
"SWADE.Benny3DFrontBumpDesc": "Rendu de texture de jetons de face",
|
||||||
|
"SWADE.Benny3DBackBumpDesc": "Rendu de texture de jetons arrière",
|
||||||
|
"SWADE.ActionTraitMod": "Modificateur de Trait d'Action",
|
||||||
|
"SWADE.ActionDmgMod": "Modificateur de dégâts",
|
||||||
|
"SWADE.ItemTraitMod": "Modificatteur de trait d'item",
|
||||||
|
"SWADE.ItemDmgMod": "Modification d'Item de dégâts",
|
||||||
|
"SWADE.Duplicates": "Doublons trouvés",
|
||||||
|
"SWADE.DuplicateItemsBodyText": "En ajoutant le {type} <strong>{name}</strong> à l'acteur {target}, les éléments dupliqués (nom/type) ont été trouvés. Les nouveaux items ont été renommés",
|
||||||
|
"SWADE.NoActionDeckFound": "Aucun jeu de cartes d'action trouvé, création en cours",
|
||||||
|
"SWADE.NoActionDeckDiscardPileFound": "Aucune défausse de carte d'action trouvée, création en cours",
|
||||||
|
"SWADE.InitDiscardPile": "Défausse de l'Initiative",
|
||||||
|
"SWADE.Wealth": "Richesse",
|
||||||
|
"SWADE.Characters": "Personnages",
|
||||||
|
"SWADE.SettingRules": "Règles d'Univers",
|
||||||
|
"SWADE.WorldBasics": "Bases du Monde",
|
||||||
|
"SWADE.CoreSkillsList": "Liste des compétences de base",
|
||||||
|
"SWADE.MAPenalty": "Pénalité d'actions multiples",
|
||||||
|
"SWADE.Mod.Custom.Add": "Ajouter un modificateur spécial",
|
||||||
|
"SWADE.Mod.Support": "Support",
|
||||||
|
"SWADE.Mod.Preset.Choose": "Choisissez une valeur pré-définie...",
|
||||||
|
"SWADE.Mod.Preset.Add": "Ajouter une valeur pré-définie",
|
||||||
|
"SWADE.Illumination._name": "Illumination",
|
||||||
|
"SWADE.Illumination.Dim": "Pénombre",
|
||||||
|
"SWADE.Illumination.Dark": "Obscurité",
|
||||||
|
"SWADE.Illumination.Pitch": "Noir",
|
||||||
|
"SWADE.Cover.Light": "Couvert léger",
|
||||||
|
"SWADE.Cover.Medium": "Couvert moyen",
|
||||||
|
"SWADE.Cover.Heavy": "Couvert important",
|
||||||
|
"SWADE.Cover.Total": "Couvert total",
|
||||||
|
"SWADE.Range.Medium": "Portée moyenne",
|
||||||
|
"SWADE.Range.Long": "Portée longue",
|
||||||
|
"SWADE.Range.Extreme": "Portée extrême",
|
||||||
|
"SWADE.ModOther": "Autres modificateurs",
|
||||||
|
"SWADE.Snapfire": "Tir Statique",
|
||||||
|
"SWADE.UnstablePlatform": "Plateforme instable",
|
||||||
|
"SWADE.CannotAddRaceToRace": "Vous ne pouvez ajouter une race/archétype à une race/archétype !",
|
||||||
|
"SWADE.ApplyEncumbrance": "Appliquer les pénalités d'Encombrement",
|
||||||
|
"SWADE.ApplyEncumbranceHint": "Appliquer les pénalités d'Encombrement. Gardez à l'esprit que cela n'effectue pas les tests de Vigueur pour résister à la Fatigue",
|
||||||
|
"SWADE.LayOutChaseWithDeck": "Utiliser les cartes pour gérer la poursuite",
|
||||||
|
"SWADE.ClearChaseCards": "Effacer les cartes de poursuite de la scène",
|
||||||
|
"SWADE.NoSceneAvailable": "Il n'y a pas de scène disponible, ou vous avez désactivez le canvas",
|
||||||
|
"SWADE.ChaseCardsCleared": "Toutes les cartes de poursuites ont été retirées de la scène.",
|
||||||
|
"SWADE.SetUpChase": "Paramétrer la poursuite",
|
||||||
|
"SWADE.NotADeckCompendium": "Aucun paquet de cartes dans le compendium selectionné",
|
||||||
|
"SWADE.ConvertToDeck": "Convertir en paquet de cartes",
|
||||||
|
"SWADE.Expiration.TabLabel": "Comportement du tour",
|
||||||
|
"SWADE.Expiration.Description": "<p>Les effets expirent lors du prochain tour de la cible, ou plus tard</p>",
|
||||||
|
"SWADE.Expiration.Behavior": "Comportement des expirations",
|
||||||
|
"SWADE.Expiration.BeginAuto": "Début du tour, automatique",
|
||||||
|
"SWADE.Expiration.BeginPrompt": "Début du tout, demande",
|
||||||
|
"SWADE.Expiration.EndAuto": "Fin du tour, automatique",
|
||||||
|
"SWADE.Expiration.EndPrompt": "Fin du tour, demande",
|
||||||
|
"SWADE.Expiration.None": "Aucun",
|
||||||
|
"SWADE.Expiration.LooseTurnOnHold": "perte du tour en attente",
|
||||||
|
"SWADE.RemoveEffectTitle": "Supprimer {label} ?",
|
||||||
|
"SWADE.RemoveEffectBody": "<p style='text-align: center;'>Supprimer <strong>{label}</strong> de <strong>{parent}</strong>?</p>",
|
||||||
|
"SWADE.PPAbbreviation": "PP",
|
||||||
|
|
||||||
|
"SWADE.ShowInChat": "Afficher dans le tchat",
|
||||||
|
"SWADE.ExpandDescription": "Agrandir pur montrer la description",
|
||||||
|
"SWADE.Favorite": "Favorite",
|
||||||
|
"SWADE.Equip": "Equiper",
|
||||||
|
"SWADE.RollDamage": "Lancer les dégats",
|
||||||
|
"SWADE.SystemLinks.Changelog": "Changelog",
|
||||||
|
"SWADE.SystemLinks.Wiki": "Wiki",
|
||||||
|
"SWADE.SystemLinks.ReportAnIssue": "Rapporter un problème",
|
||||||
|
"SWADE.Keybindings.OpenFavoriteCards.Name": "Ouvrir la main préférée",
|
||||||
|
"SWADE.Keybindings.OpenFavoriteCards.UserConfigLabel": "Main préférée",
|
||||||
|
"SWADE.Keybindings.OpenFavoriteCards.Hint": "Vous pouvez paramétrer votre main préférée dans la configuration utilisateur",
|
||||||
|
"SWADE.Keybindings.OpenFavoriteCards.NoCardsWarning": "Vous n'avez pas de main préférée",
|
||||||
|
"SWADE.Keybindings.Bennies.Name": "Dépenser/Recevoir un Jeton",
|
||||||
|
"SWADE.Keybindings.Bennies.Hint": "Appuyer pour dépenser un Jeton, gardez ALT appuyez tout en cliquant pour recevoir un Jeton",
|
||||||
|
"SWADE.OpenOrigin": "Ouvrir l'origine",
|
||||||
|
"SWADE.EffectsTemporary": "Effets temporaires",
|
||||||
|
"SWADE.EffectsPermanent": "Effets permanents",
|
||||||
|
"SWADE.Ranks.Novice": "Novice",
|
||||||
|
"SWADE.Ranks.Seasoned": "Aguerri",
|
||||||
|
"SWADE.Ranks.Veteran": "Vétéran",
|
||||||
|
"SWADE.Ranks.Heroic": "Héroïque",
|
||||||
|
"SWADE.Ranks.Legendary": "Légendaire",
|
||||||
|
"SWADE.Advances.EditorTitle": "Editeur avancé",
|
||||||
|
"SWADE.Advances.Toggle": "Activer/Desactiver le plan de progression",
|
||||||
|
"SWADE.Advances.Delete": "Supprimer la progression",
|
||||||
|
"SWADE.Advances.Planned": "Planifié",
|
||||||
|
"SWADE.Advances.Modes.Legacy": "Normal",
|
||||||
|
"SWADE.Advances.Modes.Expanded": "Etendu",
|
||||||
|
"SWADE.Advances.Types.Edge": "Nouvel atout",
|
||||||
|
"SWADE.Advances.Types.SingleSkill": "Augmentation d'une Compétence",
|
||||||
|
"SWADE.Advances.Types.TwoSkills": "Augmentation de 2 Compétences",
|
||||||
|
"SWADE.Advances.Types.Attribute": "Augmentation d'un Attribut",
|
||||||
|
"SWADE.Advances.Types.Hindrance": "Réduire un Handicap",
|
||||||
|
"SWADE.AddAdvance": "Ajouter une progression",
|
||||||
|
"SWADE.Appearance": "Apparence",
|
||||||
|
"SWADE.CharacterGoals": "Objectifs",
|
||||||
|
"SWADE.Background": "Background",
|
||||||
|
"SWADE.ActiveEffects.Add": "Ajouter un Active Effect",
|
||||||
|
"SWADE.ActiveEffects.Source": "Source",
|
||||||
|
"SWADE.Advances.Number": "Numéro d'avancement",
|
||||||
|
|
||||||
|
"Actor": "Acteur",
|
||||||
|
"Vehicles": "Véhicules",
|
||||||
|
"Ground Vehicles": "Véhicules terrestres",
|
||||||
|
"Civilian Vehicles": "Véhicules civils",
|
||||||
|
"Futuristic Military Vehicles": "Véhicules militaires futuristes",
|
||||||
|
"World War II Military Vehicles": "Véhicules militaires de la Seconde Guerre mondiale",
|
||||||
|
"Aircraft": "Aviation",
|
||||||
|
"Civilian": "Civil",
|
||||||
|
"Bestiary": "Bestiaire",
|
||||||
|
"Modern Military Aircraft": "Avions militaires modernes",
|
||||||
|
"World War II Military Aircraft": "Avions Seconde Guerre mondiale",
|
||||||
|
"Watercraft": "Maritime",
|
||||||
|
"Equipment": "Equipement",
|
||||||
|
"Armor": "Armures",
|
||||||
|
"Ammo": "Munitions",
|
||||||
|
"Common Gear": "Matériel de base",
|
||||||
|
"Modern Firearms": "Armes à feu modernes",
|
||||||
|
"Personal Weapons": "Armes de contact",
|
||||||
|
"Special Weapons": "Armes spéciales",
|
||||||
|
"Natural/Improvised Weapons": "Armes naturelles/improvisées",
|
||||||
|
"Skills": "Compétences",
|
||||||
|
"Edges": "Atouts",
|
||||||
|
"Background Edges": "Atouts de background",
|
||||||
|
"Combat Edges": "Atouts de combat",
|
||||||
|
"Leadership Edges": "Atouts de commandement",
|
||||||
|
"Legendary Edges": "Atouts légendaires",
|
||||||
|
"Power Edges": "Atouts de pouvoirs",
|
||||||
|
"Professional Edges": "Atouts professionnels",
|
||||||
|
"Social Edges": "Atouts sociaux",
|
||||||
|
"Weird Edges": "Atouts étranges",
|
||||||
|
"Hindrances": "Handicaps",
|
||||||
|
"Powers": "Pouvoirs",
|
||||||
|
"Special Abilities": "Capacités spéciales",
|
||||||
|
"1. Characters": "1. Personnages",
|
||||||
|
"2. Gear": "2. Matériel",
|
||||||
|
"3. Rules": "3. Règles",
|
||||||
|
"5. Powers": "5. Pouvoirs",
|
||||||
|
"6. Bestiary": "6. Bestiaire",
|
||||||
|
"7. Game Mastering": "6. Conseils aux Maîtres de Jeu",
|
||||||
|
"Character Creation": "Création de personnages",
|
||||||
|
"The Adventure toolkit": "Boite à outils des aventures"
|
||||||
}
|
}
|
||||||
|
14
module.json
14
module.json
@ -1,10 +1,11 @@
|
|||||||
{
|
{
|
||||||
"name": "swade-fr",
|
"name": "swade-fr",
|
||||||
"title": "SWADE - Traduction française",
|
"title": "SWADE - Traduction française",
|
||||||
"description": "Ajoute le français (FRANCE) au système SWADE.<p> Une traduction Babele des compendiums est inclue mais optionnelle. (Peut rentrer en conflit avec les objets des compendiums venant du module Core Rules sur les fiches de personnage, Babele traduisant bêtement les objets quand vous appuyez sur le bouton Traduire.) </p> <p>*** Join the official Discord server: <a href='https://discord.gg/foundryvtt'> Official Discord</a></p><p>*** Rejoignez la communauté Francophone: <a href='https://discord.gg/pPSDNJk'>Discord francophone</a></p>",
|
"description": "Ajoute le français (FRANCE) au système SWADE.<p> Une traduction Babele des compendiums est inclue mais optionnelle. (Encore en test, à utiliser à vos risques et périls !) </p> <p>*** Join the official Discord server: <a href='https://discord.gg/foundryvtt'> Official Discord</a></p><p>*** Rejoignez la communauté Francophone: <a href='https://discord.gg/pPSDNJk'>Discord francophone</a></p>",
|
||||||
"version": "0.17.2.4",
|
"version": "0.21.5.0",
|
||||||
"minimumCoreVersion" : "0.7.9",
|
"minimumCoreVersion" : "0.7.9",
|
||||||
"compatibleCoreVersion" : "0.8.9",
|
"compatibleCoreVersion" : "9",
|
||||||
|
"author": "BoboursToutCool, Gronyon, Kyane, LeRatierBretonnien, Sasmira, U~man,X.O. de Vorcen, Arnok13",
|
||||||
"authors": [
|
"authors": [
|
||||||
{
|
{
|
||||||
"name": "BoboursToutCool",
|
"name": "BoboursToutCool",
|
||||||
@ -60,8 +61,7 @@
|
|||||||
"path": "fr.json"
|
"path": "fr.json"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"url": "https://www.uberwald.me/gitea/public//foundryvtt-swade-fr",
|
||||||
"url": "https://gitlab.com/mesfoliesludiques/foundryvtt-swade-fr",
|
"manifest": "https://www.uberwald.me/gitea/public/foundryvtt-swade-fr/raw/branch/master/module.json",
|
||||||
"manifest": "https://gitlab.com/mesfoliesludiques/foundryvtt-swade-fr/-/raw/master/module.json",
|
"download": "https://www.uberwald.me/gitea/public/foundryvtt-swade-fr/archive/foundryvtt-swade-fr-0.21.5.0.zip"
|
||||||
"download": "https://gitlab.com/mesfoliesludiques/foundryvtt-swade-fr/-/archive/master/foundryvtt-swade-fr-master.zip"
|
|
||||||
}
|
}
|
||||||
|
39
tools/detect_missing_strings.lua
Normal file
39
tools/detect_missing_strings.lua
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
package.path = package.path .. ";luajson/?.lua"
|
||||||
|
local JSON = require"json"
|
||||||
|
|
||||||
|
local enjsonf = "../../swade/src/lang/en.yml"
|
||||||
|
local frjsonf = "../fr.json"
|
||||||
|
|
||||||
|
local fp = io.open(enjsonf, "r")
|
||||||
|
local line = fp:read()
|
||||||
|
local entags = {}
|
||||||
|
while line do
|
||||||
|
--print("LINE", line)
|
||||||
|
local key, value = line:match("([%w%.]*):([>%-%+%p%s%w%d%.]*)" )
|
||||||
|
if key then
|
||||||
|
entags[key] = value
|
||||||
|
end
|
||||||
|
line = fp:read()
|
||||||
|
end
|
||||||
|
fp:close()
|
||||||
|
|
||||||
|
fp = io.open(frjsonf, "r")
|
||||||
|
local frtags = JSON.decode( fp:read("*a") )
|
||||||
|
fp:close()
|
||||||
|
|
||||||
|
local todisplay = {}
|
||||||
|
for tag, value in pairs(entags) do
|
||||||
|
if not frtags[tag] then
|
||||||
|
todisplay[#todisplay+1] = { tag=tag, value=value }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
table.sort(todisplay, function (a, b)
|
||||||
|
return a.tag < b.tag
|
||||||
|
end
|
||||||
|
)
|
||||||
|
for _, tagDef in pairs(todisplay) do
|
||||||
|
print('"'.. tagDef.tag ..'":"'.. tagDef.value..'",')
|
||||||
|
end
|
||||||
|
|
||||||
|
|
625
tools/lpeg/lpcap.lua
Normal file
625
tools/lpeg/lpcap.lua
Normal file
@ -0,0 +1,625 @@
|
|||||||
|
--[[
|
||||||
|
LPEGLJ
|
||||||
|
lpcap.lua
|
||||||
|
Capture functions
|
||||||
|
Copyright (C) 2014 Rostislav Sacek.
|
||||||
|
based on LPeg v1.0 - PEG pattern matching for Lua
|
||||||
|
Lua.org & PUC-Rio written by Roberto Ierusalimschy
|
||||||
|
http://www.inf.puc-rio.br/~roberto/lpeg/
|
||||||
|
|
||||||
|
** 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.
|
||||||
|
**
|
||||||
|
** [ MIT license: http://www.opensource.org/licenses/mit-license.php ]
|
||||||
|
--]]
|
||||||
|
local ffi = require "ffi"
|
||||||
|
|
||||||
|
local Cclose = 0
|
||||||
|
local Cposition = 1
|
||||||
|
local Cconst = 2
|
||||||
|
local Cbackref = 3
|
||||||
|
local Carg = 4
|
||||||
|
local Csimple = 5
|
||||||
|
local Ctable = 6
|
||||||
|
local Cfunction = 7
|
||||||
|
local Cquery = 8
|
||||||
|
local Cstring = 9
|
||||||
|
local Cnum = 10
|
||||||
|
local Csubst = 11
|
||||||
|
local Cfold = 12
|
||||||
|
local Cruntime = 13
|
||||||
|
local Cgroup = 14
|
||||||
|
|
||||||
|
local MAXSTRCAPS = 10
|
||||||
|
|
||||||
|
local pushcapture
|
||||||
|
local addonestring
|
||||||
|
|
||||||
|
|
||||||
|
-- Goes back in a list of captures looking for an open capture
|
||||||
|
-- corresponding to a close
|
||||||
|
|
||||||
|
local function findopen(cs, index)
|
||||||
|
local n = 0; -- number of closes waiting an open
|
||||||
|
while true do
|
||||||
|
index = index - 1
|
||||||
|
if cs.ocap[index].kind == Cclose then
|
||||||
|
n = n + 1 -- one more open to skip
|
||||||
|
elseif cs.ocap[index].siz == 0 then
|
||||||
|
if n == 0 then
|
||||||
|
return index
|
||||||
|
end
|
||||||
|
n = n - 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local function checknextcap(cs, captop)
|
||||||
|
local cap = cs.cap;
|
||||||
|
-- not a single capture? ((cap)->siz != 0)
|
||||||
|
if cs.ocap[cap].siz == 0 then
|
||||||
|
local n = 0; -- number of opens waiting a close
|
||||||
|
-- look for corresponding close
|
||||||
|
while true do
|
||||||
|
cap = cap + 1
|
||||||
|
if cap > captop then return end
|
||||||
|
if cs.ocap[cap].kind == Cclose then
|
||||||
|
n = n - 1
|
||||||
|
if n + 1 == 0 then
|
||||||
|
break;
|
||||||
|
end
|
||||||
|
elseif cs.ocap[cap].siz == 0 then
|
||||||
|
n = n + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
cap = cap + 1; -- + 1 to skip last close (or entire single capture)
|
||||||
|
if cap > captop then return end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- Go to the next capture
|
||||||
|
|
||||||
|
local function nextcap(cs)
|
||||||
|
local cap = cs.cap;
|
||||||
|
-- not a single capture? ((cap)->siz != 0)
|
||||||
|
if cs.ocap[cap].siz == 0 then
|
||||||
|
local n = 0; -- number of opens waiting a close
|
||||||
|
-- look for corresponding close
|
||||||
|
while true do
|
||||||
|
cap = cap + 1
|
||||||
|
if cs.ocap[cap].kind == Cclose then
|
||||||
|
n = n - 1
|
||||||
|
if n + 1 == 0 then
|
||||||
|
break;
|
||||||
|
end
|
||||||
|
elseif cs.ocap[cap].siz == 0 then
|
||||||
|
n = n + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
cs.cap = cap + 1; -- + 1 to skip last close (or entire single capture)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- Push on the Lua stack all values generated by nested captures inside
|
||||||
|
-- the current capture. Returns number of values pushed. 'addextra'
|
||||||
|
-- makes it push the entire match after all captured values. The
|
||||||
|
-- entire match is pushed also if there are no other nested values,
|
||||||
|
-- so the function never returns zero.
|
||||||
|
|
||||||
|
local function pushnestedvalues(cs, addextra, out, valuetable)
|
||||||
|
local co = cs.cap
|
||||||
|
cs.cap = cs.cap + 1
|
||||||
|
-- no nested captures?
|
||||||
|
if cs.ocap[cs.cap - 1].siz ~= 0 then
|
||||||
|
local st = cs.ocap[co].s
|
||||||
|
local l = cs.ocap[co].siz - 1
|
||||||
|
out.outindex = out.outindex + 1
|
||||||
|
out.out[out.outindex] = cs.s and cs.s:sub(st, st + l - 1) or cs.stream(st, st + l - 1)
|
||||||
|
return 1; -- that is it
|
||||||
|
else
|
||||||
|
local n = 0;
|
||||||
|
while cs.ocap[cs.cap].kind ~= Cclose do -- repeat for all nested patterns
|
||||||
|
n = n + pushcapture(cs, out, valuetable);
|
||||||
|
end
|
||||||
|
-- need extra?
|
||||||
|
if addextra or n == 0 then
|
||||||
|
local st = cs.ocap[co].s
|
||||||
|
local l = cs.ocap[cs.cap].s - cs.ocap[co].s
|
||||||
|
out.outindex = out.outindex + 1
|
||||||
|
out.out[out.outindex] = cs.s and cs.s:sub(st, st + l - 1) or cs.stream(st, st + l - 1)
|
||||||
|
n = n + 1
|
||||||
|
end
|
||||||
|
cs.cap = cs.cap + 1 -- skip close entry
|
||||||
|
return n;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- Push only the first value generated by nested captures
|
||||||
|
|
||||||
|
local function pushonenestedvalue(cs, out, valuetable)
|
||||||
|
local n = pushnestedvalues(cs, false, out, valuetable)
|
||||||
|
for i = n, 2, -1 do
|
||||||
|
out.out[out.outindex] = nil
|
||||||
|
out.outindex = out.outindex - 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- Try to find a named group capture with the name given at the top of
|
||||||
|
-- the stack; goes backward from 'cap'.
|
||||||
|
|
||||||
|
local function findback(cs, cap, name, valuetable)
|
||||||
|
-- repeat until end of list
|
||||||
|
while cap > 0 do
|
||||||
|
cap = cap - 1
|
||||||
|
local continue
|
||||||
|
if cs.ocap[cap].kind == Cclose then
|
||||||
|
cap = findopen(cs, cap); -- skip nested captures
|
||||||
|
elseif cs.ocap[cap].siz == 0 then
|
||||||
|
continue = true -- opening an enclosing capture: skip and get previous
|
||||||
|
end
|
||||||
|
if not continue and cs.ocap[cap].kind == Cgroup and cs.ocap[cap].idx ~= 0 then
|
||||||
|
local gname = valuetable[cs.ocap[cap].idx] -- get group name
|
||||||
|
-- right group?
|
||||||
|
if name == gname then
|
||||||
|
return cap;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
error(("back reference '%s' not found"):format(name), 0)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- Back-reference capture. Return number of values pushed.
|
||||||
|
|
||||||
|
local function backrefcap(cs, out, valuetable)
|
||||||
|
local curr = cs.cap;
|
||||||
|
local name = valuetable[cs.ocap[cs.cap].idx] -- reference name
|
||||||
|
cs.cap = findback(cs, curr, name, valuetable) -- find corresponding group
|
||||||
|
local n = pushnestedvalues(cs, false, out, valuetable); -- push group's values
|
||||||
|
cs.cap = curr + 1;
|
||||||
|
return n;
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- Table capture: creates a new table and populates it with nested
|
||||||
|
-- captures.
|
||||||
|
|
||||||
|
local function tablecap(cs, out, valuetable)
|
||||||
|
local n = 0;
|
||||||
|
local t = {}
|
||||||
|
cs.cap = cs.cap + 1
|
||||||
|
-- table is empty
|
||||||
|
if cs.ocap[cs.cap - 1].siz == 0 then
|
||||||
|
while cs.ocap[cs.cap].kind ~= Cclose do
|
||||||
|
local subout = { outindex = 0, out = {} }
|
||||||
|
-- named group?
|
||||||
|
if cs.ocap[cs.cap].kind == Cgroup and cs.ocap[cs.cap].idx ~= 0 then
|
||||||
|
local groupname = valuetable[cs.ocap[cs.cap].idx] -- push group name
|
||||||
|
pushonenestedvalue(cs, subout, valuetable)
|
||||||
|
t[groupname] = subout.out[1]
|
||||||
|
else
|
||||||
|
-- not a named group
|
||||||
|
local k = pushcapture(cs, subout, valuetable)
|
||||||
|
-- store all values into table
|
||||||
|
for i = 1, subout.outindex do
|
||||||
|
t[i + n] = subout.out[i]
|
||||||
|
end
|
||||||
|
n = n + k;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
cs.cap = cs.cap + 1 -- skip close entry
|
||||||
|
end
|
||||||
|
out.outindex = out.outindex + 1
|
||||||
|
out.out[out.outindex] = t
|
||||||
|
return 1; -- number of values pushed (only the table)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- Table-query capture
|
||||||
|
|
||||||
|
local function querycap(cs, out, valuetable)
|
||||||
|
local table = valuetable[cs.ocap[cs.cap].idx]
|
||||||
|
local subout = { outindex = 0, out = {} }
|
||||||
|
pushonenestedvalue(cs, subout, valuetable) -- get nested capture
|
||||||
|
-- query cap. value at table
|
||||||
|
if table[subout.out[1]] ~= nil then
|
||||||
|
out.outindex = out.outindex + 1
|
||||||
|
out.out[out.outindex] = table[subout.out[1]]
|
||||||
|
return 1
|
||||||
|
end
|
||||||
|
return 0
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- Fold capture
|
||||||
|
|
||||||
|
local function foldcap(cs, out, valuetable)
|
||||||
|
local fce = valuetable[cs.ocap[cs.cap].idx]
|
||||||
|
cs.cap = cs.cap + 1
|
||||||
|
-- no nested captures?
|
||||||
|
-- or no nested captures (large subject)?
|
||||||
|
if cs.ocap[cs.cap - 1].siz ~= 0 or
|
||||||
|
cs.ocap[cs.cap].kind == Cclose then
|
||||||
|
error("no initial value for fold capture", 0);
|
||||||
|
end
|
||||||
|
local subout = { outindex = 0; out = {} }
|
||||||
|
local n = pushcapture(cs, subout, valuetable) -- nested captures with no values?
|
||||||
|
if n == 0 then
|
||||||
|
error("no initial value for fold capture", 0);
|
||||||
|
end
|
||||||
|
local acumulator = subout.out[1] -- leave only one result for accumulator
|
||||||
|
while cs.ocap[cs.cap].kind ~= Cclose do
|
||||||
|
local subout = { outindex = 0; out = {} }
|
||||||
|
n = pushcapture(cs, subout, valuetable); -- get next capture's values
|
||||||
|
acumulator = fce(acumulator, unpack(subout.out, 1, subout.outindex)) -- call folding function
|
||||||
|
end
|
||||||
|
cs.cap = cs.cap + 1; -- skip close entry
|
||||||
|
out.outindex = out.outindex + 1
|
||||||
|
out.out[out.outindex] = acumulator
|
||||||
|
return 1; -- only accumulator left on the stack
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local function retcount(...)
|
||||||
|
return select('#', ...), { ... }
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- Function capture
|
||||||
|
|
||||||
|
local function functioncap(cs, out, valuetable)
|
||||||
|
local fce = valuetable[cs.ocap[cs.cap].idx] -- push function
|
||||||
|
local subout = { outindex = 0, out = {} }
|
||||||
|
local n = pushnestedvalues(cs, false, subout, valuetable); -- push nested captures
|
||||||
|
local count, ret = retcount(fce(unpack(subout.out, 1, n))) -- call function
|
||||||
|
for i = 1, count do
|
||||||
|
out.outindex = out.outindex + 1
|
||||||
|
out.out[out.outindex] = ret[i]
|
||||||
|
end
|
||||||
|
return count
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- Select capture
|
||||||
|
|
||||||
|
local function numcap(cs, out, valuetable)
|
||||||
|
local idx = valuetable[cs.ocap[cs.cap].idx] -- value to select
|
||||||
|
-- no values?
|
||||||
|
if idx == 0 then
|
||||||
|
nextcap(cs); -- skip entire capture
|
||||||
|
return 0; -- no value produced
|
||||||
|
else
|
||||||
|
local subout = { outindex = 0, out = {} }
|
||||||
|
local n = pushnestedvalues(cs, false, subout, valuetable)
|
||||||
|
-- invalid index?
|
||||||
|
if n < idx then
|
||||||
|
error(("no capture '%d'"):format(idx), 0)
|
||||||
|
else
|
||||||
|
out.outindex = out.outindex + 1
|
||||||
|
out.out[out.outindex] = subout.out[idx] -- get selected capture
|
||||||
|
return 1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- Calls a runtime capture. Returns number of captures removed by
|
||||||
|
-- the call, including the initial Cgroup. (Captures to be added are
|
||||||
|
-- on the Lua stack.)
|
||||||
|
|
||||||
|
local function runtimecap(cs, close, s, out, valuetable)
|
||||||
|
local open = findopen(cs, close)
|
||||||
|
assert(cs.ocap[open].kind == Cgroup)
|
||||||
|
cs.ocap[close].kind = Cclose; -- closes the group
|
||||||
|
cs.ocap[close].s = s;
|
||||||
|
cs.cap = open;
|
||||||
|
local fce = valuetable[cs.ocap[cs.cap].idx] -- push function to be called
|
||||||
|
local subout = { outindex = 0, out = {} }
|
||||||
|
local n = pushnestedvalues(cs, false, subout, valuetable); -- push nested captures
|
||||||
|
local count, ret = retcount(fce(cs.s or cs.stream, s, unpack(subout.out, 1, n))) -- call dynamic function
|
||||||
|
for i = 1, count do
|
||||||
|
out.outindex = out.outindex + 1
|
||||||
|
out.out[out.outindex] = ret[i]
|
||||||
|
end
|
||||||
|
return close - open -- number of captures of all kinds removed
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Collect values from current capture into array 'cps'. Current
|
||||||
|
-- capture must be Cstring (first call) or Csimple (recursive calls).
|
||||||
|
-- (In first call, fills %0 with whole match for Cstring.)
|
||||||
|
-- Returns number of elements in the array that were filled.
|
||||||
|
|
||||||
|
local function getstrcaps(cs, cps, n)
|
||||||
|
local k = n
|
||||||
|
n = n + 1
|
||||||
|
cps[k + 1].isstring = true; -- get string value
|
||||||
|
cps[k + 1].startstr = cs.ocap[cs.cap].s; -- starts here
|
||||||
|
cs.cap = cs.cap + 1
|
||||||
|
-- nested captures?
|
||||||
|
if cs.ocap[cs.cap - 1].siz == 0 then
|
||||||
|
-- traverse them
|
||||||
|
while cs.ocap[cs.cap].kind ~= Cclose do
|
||||||
|
-- too many captures?
|
||||||
|
if n >= MAXSTRCAPS then
|
||||||
|
nextcap(cs); -- skip extra captures (will not need them)
|
||||||
|
elseif cs.ocap[cs.cap].kind == Csimple then
|
||||||
|
-- string?
|
||||||
|
n = getstrcaps(cs, cps, n); -- put info. into array
|
||||||
|
else
|
||||||
|
cps[n + 1].isstring = false; -- not a string
|
||||||
|
cps[n + 1].origcap = cs.cap; -- keep original capture
|
||||||
|
nextcap(cs);
|
||||||
|
n = n + 1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
cs.cap = cs.cap + 1 -- skip close
|
||||||
|
end
|
||||||
|
cps[k + 1].endstr = cs.ocap[cs.cap - 1].s + cs.ocap[cs.cap - 1].siz - 1 -- ends here
|
||||||
|
return n;
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- add next capture value (which should be a string) to buffer 'b'
|
||||||
|
|
||||||
|
-- String capture: add result to buffer 'b' (instead of pushing
|
||||||
|
-- it into the stack)
|
||||||
|
|
||||||
|
local function stringcap(cs, b, valuetable)
|
||||||
|
local cps = {}
|
||||||
|
for i = 1, MAXSTRCAPS do
|
||||||
|
cps[#cps + 1] = {}
|
||||||
|
end
|
||||||
|
local fmt = valuetable[cs.ocap[cs.cap].idx]
|
||||||
|
local n = getstrcaps(cs, cps, 0) - 1; -- collect nested captures
|
||||||
|
local i = 1
|
||||||
|
-- traverse them
|
||||||
|
while i <= #fmt do
|
||||||
|
local c = fmt:sub(i, i)
|
||||||
|
-- not an escape?
|
||||||
|
if c ~= '%' then
|
||||||
|
b[#b + 1] = c -- add it to buffer
|
||||||
|
elseif fmt:sub(i + 1, i + 1) < '0' or fmt:sub(i + 1, i + 1) > '9' then
|
||||||
|
-- not followed by a digit?
|
||||||
|
i = i + 1
|
||||||
|
b[#b + 1] = fmt:sub(i, i)
|
||||||
|
else
|
||||||
|
i = i + 1
|
||||||
|
local l = fmt:sub(i, i) - '0'; -- capture index
|
||||||
|
if l > n then
|
||||||
|
error(("invalid capture index (%d)"):format(l), 0)
|
||||||
|
elseif cps[l + 1].isstring then
|
||||||
|
b[#b + 1] = cs.s and cs.s:sub(cps[l + 1].startstr, cps[l + 1].endstr - cps[l + 1].startstr + cps[l + 1].startstr - 1) or
|
||||||
|
cs.stream(cps[l + 1].startstr, cps[l + 1].endstr - cps[l + 1].startstr + cps[l + 1].startstr - 1)
|
||||||
|
else
|
||||||
|
local curr = cs.cap;
|
||||||
|
cs.cap = cps[l + 1].origcap; -- go back to evaluate that nested capture
|
||||||
|
if not addonestring(cs, b, "capture", valuetable) then
|
||||||
|
error(("no values in capture index %d"):format(l), 0)
|
||||||
|
end
|
||||||
|
cs.cap = curr; -- continue from where it stopped
|
||||||
|
end
|
||||||
|
end
|
||||||
|
i = i + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- Substitution capture: add result to buffer 'b'
|
||||||
|
|
||||||
|
local function substcap(cs, b, valuetable)
|
||||||
|
local curr = cs.ocap[cs.cap].s;
|
||||||
|
-- no nested captures?
|
||||||
|
if cs.ocap[cs.cap].siz ~= 0 then
|
||||||
|
-- keep original text
|
||||||
|
b[#b + 1] = cs.s and cs.s:sub(curr, cs.ocap[cs.cap].siz - 1 + curr - 1) or
|
||||||
|
cs.stream(curr, cs.ocap[cs.cap].siz - 1 + curr - 1)
|
||||||
|
else
|
||||||
|
cs.cap = cs.cap + 1 -- skip open entry
|
||||||
|
-- traverse nested captures
|
||||||
|
while cs.ocap[cs.cap].kind ~= Cclose do
|
||||||
|
local next = cs.ocap[cs.cap].s;
|
||||||
|
b[#b + 1] = cs.s and cs.s:sub(curr, next - curr + curr - 1) or
|
||||||
|
cs.stream(curr, next - curr + curr - 1) -- add text up to capture
|
||||||
|
if addonestring(cs, b, "replacement", valuetable) then
|
||||||
|
curr = cs.ocap[cs.cap - 1].s + cs.ocap[cs.cap - 1].siz - 1; -- continue after match
|
||||||
|
else
|
||||||
|
-- no capture value
|
||||||
|
curr = next; -- keep original text in final result
|
||||||
|
end
|
||||||
|
end
|
||||||
|
b[#b + 1] = cs.s and cs.s:sub(curr, curr + cs.ocap[cs.cap].s - curr - 1) or
|
||||||
|
cs.stream(curr, curr + cs.ocap[cs.cap].s - curr - 1) -- add last piece of text
|
||||||
|
end
|
||||||
|
cs.cap = cs.cap + 1 -- go to next capture
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- Evaluates a capture and adds its first value to buffer 'b'; returns
|
||||||
|
-- whether there was a value
|
||||||
|
|
||||||
|
function addonestring(cs, b, what, valuetable)
|
||||||
|
local tag = cs.ocap[cs.cap].kind
|
||||||
|
if tag == Cstring then
|
||||||
|
stringcap(cs, b, valuetable); -- add capture directly to buffer
|
||||||
|
return 1
|
||||||
|
elseif tag == Csubst then
|
||||||
|
substcap(cs, b, valuetable); -- add capture directly to buffer
|
||||||
|
return 1
|
||||||
|
else
|
||||||
|
local subout = { outindex = 0, out = {} }
|
||||||
|
local n = pushcapture(cs, subout, valuetable);
|
||||||
|
if n > 0 then
|
||||||
|
if type(subout.out[1]) ~= 'string' and type(subout.out[1]) ~= 'number' then
|
||||||
|
error(("invalid %s value (a %s)"):format(what, type(subout.out[1])), 0)
|
||||||
|
end
|
||||||
|
b[#b + 1] = subout.out[1]
|
||||||
|
return n
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- Push all values of the current capture into the stack; returns
|
||||||
|
-- number of values pushed
|
||||||
|
|
||||||
|
function pushcapture(cs, out, valuetable)
|
||||||
|
local type = cs.ocap[cs.cap].kind
|
||||||
|
if type == Cposition then
|
||||||
|
out.outindex = out.outindex + 1
|
||||||
|
out.out[out.outindex] = cs.ocap[cs.cap].s
|
||||||
|
cs.cap = cs.cap + 1;
|
||||||
|
return 1;
|
||||||
|
elseif type == Cconst then
|
||||||
|
out.outindex = out.outindex + 1
|
||||||
|
out.out[out.outindex] = valuetable[cs.ocap[cs.cap].idx]
|
||||||
|
cs.cap = cs.cap + 1
|
||||||
|
return 1;
|
||||||
|
elseif type == Carg then
|
||||||
|
local arg = valuetable[cs.ocap[cs.cap].idx]
|
||||||
|
cs.cap = cs.cap + 1
|
||||||
|
if arg > cs.ptopcount then
|
||||||
|
error(("reference to absent extra argument #%d"):format(arg), 0)
|
||||||
|
end
|
||||||
|
out.outindex = out.outindex + 1
|
||||||
|
out.out[out.outindex] = cs.ptop[arg]
|
||||||
|
return 1;
|
||||||
|
elseif type == Csimple then
|
||||||
|
local k = pushnestedvalues(cs, true, out, valuetable)
|
||||||
|
local index = out.outindex
|
||||||
|
table.insert(out.out, index - k + 1, out.out[index])
|
||||||
|
out[index + 1] = nil
|
||||||
|
return k;
|
||||||
|
elseif type == Cruntime then
|
||||||
|
out.outindex = out.outindex + 1
|
||||||
|
out.out[out.outindex] = valuetable[cs.ocap[cs.cap].idx]
|
||||||
|
cs.cap = cs.cap + 1;
|
||||||
|
return 1;
|
||||||
|
elseif type == Cstring then
|
||||||
|
local b = {}
|
||||||
|
stringcap(cs, b, valuetable)
|
||||||
|
out.outindex = out.outindex + 1
|
||||||
|
out.out[out.outindex] = table.concat(b)
|
||||||
|
return 1;
|
||||||
|
elseif type == Csubst then
|
||||||
|
local b = {}
|
||||||
|
substcap(cs, b, valuetable);
|
||||||
|
out.outindex = out.outindex + 1
|
||||||
|
out.out[out.outindex] = table.concat(b)
|
||||||
|
return 1;
|
||||||
|
elseif type == Cgroup then
|
||||||
|
-- anonymous group?
|
||||||
|
if cs.ocap[cs.cap].idx == 0 then
|
||||||
|
return pushnestedvalues(cs, false, out, valuetable); -- add all nested values
|
||||||
|
else
|
||||||
|
-- named group: add no values
|
||||||
|
nextcap(cs); -- skip capture
|
||||||
|
return 0
|
||||||
|
end
|
||||||
|
elseif type == Cbackref then
|
||||||
|
return backrefcap(cs, out, valuetable)
|
||||||
|
elseif type == Ctable then
|
||||||
|
return tablecap(cs, out, valuetable)
|
||||||
|
elseif type == Cfunction then
|
||||||
|
return functioncap(cs, out, valuetable)
|
||||||
|
elseif type == Cnum then
|
||||||
|
return numcap(cs, out, valuetable)
|
||||||
|
elseif type == Cquery then
|
||||||
|
return querycap(cs, out, valuetable)
|
||||||
|
elseif type == Cfold then
|
||||||
|
return foldcap(cs, out, valuetable)
|
||||||
|
else
|
||||||
|
assert(false)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- Prepare a CapState structure and traverse the entire list of
|
||||||
|
-- captures in the stack pushing its results. 's' is the subject
|
||||||
|
-- string, 'r' is the final position of the match, and 'ptop'
|
||||||
|
-- the index in the stack where some useful values were pushed.
|
||||||
|
-- Returns the number of results pushed. (If the list produces no
|
||||||
|
-- results, push the final position of the match.)
|
||||||
|
|
||||||
|
local function getcaptures(capture, s, stream, r, valuetable, ...)
|
||||||
|
local n = 0;
|
||||||
|
local cs = { cap = 0 }
|
||||||
|
local out = { outindex = 0; out = {} }
|
||||||
|
-- is there any capture?
|
||||||
|
if capture[cs.cap].kind ~= Cclose then
|
||||||
|
cs.ocap = capture
|
||||||
|
cs.s = s;
|
||||||
|
cs.stream = stream
|
||||||
|
cs.ptopcount, cs.ptop = retcount(...)
|
||||||
|
repeat -- collect their values
|
||||||
|
n = n + pushcapture(cs, out, valuetable)
|
||||||
|
until cs.ocap[cs.cap].kind == Cclose
|
||||||
|
end
|
||||||
|
-- no capture values?
|
||||||
|
if n == 0 then
|
||||||
|
if not r then
|
||||||
|
return
|
||||||
|
else
|
||||||
|
return r
|
||||||
|
end
|
||||||
|
end
|
||||||
|
assert(out.outindex < 7998, "(too many captures)")
|
||||||
|
return unpack(out.out, 1, out.outindex)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function getcapturesruntime(capture, s, stream, notdelete, min, max, captop, valuetable, ...)
|
||||||
|
local n = 0;
|
||||||
|
local cs = { cap = min }
|
||||||
|
local out = { outindex = 0; out = {} }
|
||||||
|
cs.ocap = capture
|
||||||
|
cs.s = s
|
||||||
|
cs.stream = stream
|
||||||
|
cs.ptopcount, cs.ptop = retcount(...)
|
||||||
|
local start = 0
|
||||||
|
repeat -- collect their values
|
||||||
|
if not checknextcap(cs, max) then break end
|
||||||
|
local notdelete = notdelete or capture[cs.cap].kind == Cgroup and capture[cs.cap].idx ~= 0 and capture[cs.cap].candelete == 0
|
||||||
|
pushcapture(cs, out, valuetable)
|
||||||
|
if notdelete then
|
||||||
|
start = cs.cap
|
||||||
|
else
|
||||||
|
n = n + cs.cap - start
|
||||||
|
for i = 0, captop - cs.cap - 1 do
|
||||||
|
ffi.copy(capture + start + i, capture + cs.cap + i, ffi.sizeof('CAPTURE'))
|
||||||
|
end
|
||||||
|
max = max - (cs.cap - start)
|
||||||
|
captop = captop - (cs.cap - start)
|
||||||
|
cs.cap = start
|
||||||
|
end
|
||||||
|
until cs.cap == max
|
||||||
|
assert(out.outindex < 7998, "(too many captures)")
|
||||||
|
return n, out.out, out.outindex
|
||||||
|
end
|
||||||
|
|
||||||
|
return {
|
||||||
|
getcaptures = getcaptures,
|
||||||
|
runtimecap = runtimecap,
|
||||||
|
getcapturesruntime = getcapturesruntime,
|
||||||
|
}
|
||||||
|
|
1057
tools/lpeg/lpcode.lua
Normal file
1057
tools/lpeg/lpcode.lua
Normal file
File diff suppressed because it is too large
Load Diff
1373
tools/lpeg/lpeg.lua
Normal file
1373
tools/lpeg/lpeg.lua
Normal file
File diff suppressed because it is too large
Load Diff
356
tools/lpeg/lpprint.lua
Normal file
356
tools/lpeg/lpprint.lua
Normal file
@ -0,0 +1,356 @@
|
|||||||
|
--[[
|
||||||
|
LPEGLJ
|
||||||
|
lpprint.lua
|
||||||
|
Tree, code and debug print function (only for debuging)
|
||||||
|
Copyright (C) 2014 Rostislav Sacek.
|
||||||
|
based on LPeg v1.0 - PEG pattern matching for Lua
|
||||||
|
Lua.org & PUC-Rio written by Roberto Ierusalimschy
|
||||||
|
http://www.inf.puc-rio.br/~roberto/lpeg/
|
||||||
|
|
||||||
|
** 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.
|
||||||
|
**
|
||||||
|
** [ MIT license: http://www.opensource.org/licenses/mit-license.php ]
|
||||||
|
--]]
|
||||||
|
|
||||||
|
local ffi = require"ffi"
|
||||||
|
local band, rshift, lshift = bit.band, bit.rshift, bit.lshift
|
||||||
|
|
||||||
|
ffi.cdef[[
|
||||||
|
int isprint ( int c );
|
||||||
|
]]
|
||||||
|
|
||||||
|
local RuleLR = 0x10000
|
||||||
|
local Ruleused = 0x20000
|
||||||
|
|
||||||
|
-- {======================================================
|
||||||
|
-- Printing patterns (for debugging)
|
||||||
|
-- =======================================================
|
||||||
|
|
||||||
|
local TChar = 0
|
||||||
|
local TSet = 1
|
||||||
|
local TAny = 2 -- standard PEG elements
|
||||||
|
local TTrue = 3
|
||||||
|
local TFalse = 4
|
||||||
|
local TRep = 5
|
||||||
|
local TSeq = 6
|
||||||
|
local TChoice = 7
|
||||||
|
local TNot = 8
|
||||||
|
local TAnd = 9
|
||||||
|
local TCall = 10
|
||||||
|
local TOpenCall = 11
|
||||||
|
local TRule = 12 -- sib1 is rule's pattern, sib2 is 'next' rule
|
||||||
|
local TGrammar = 13 -- sib1 is initial (and first) rule
|
||||||
|
local TBehind = 14 -- match behind
|
||||||
|
local TCapture = 15 -- regular capture
|
||||||
|
local TRunTime = 16 -- run-time capture
|
||||||
|
|
||||||
|
local IAny = 0 -- if no char, fail
|
||||||
|
local IChar = 1 -- if char != aux, fail
|
||||||
|
local ISet = 2 -- if char not in val, fail
|
||||||
|
local ITestAny = 3 -- in no char, jump to 'offset'
|
||||||
|
local ITestChar = 4 -- if char != aux, jump to 'offset'
|
||||||
|
local ITestSet = 5 -- if char not in val, jump to 'offset'
|
||||||
|
local ISpan = 6 -- read a span of chars in val
|
||||||
|
local IBehind = 7 -- walk back 'aux' characters (fail if not possible)
|
||||||
|
local IRet = 8 -- return from a rule
|
||||||
|
local IEnd = 9 -- end of pattern
|
||||||
|
local IChoice = 10 -- stack a choice; next fail will jump to 'offset'
|
||||||
|
local IJmp = 11 -- jump to 'offset'
|
||||||
|
local ICall = 12 -- call rule at 'offset'
|
||||||
|
local IOpenCall = 13 -- call rule number 'offset' (must be closed to a ICall)
|
||||||
|
local ICommit = 14 -- pop choice and jump to 'offset'
|
||||||
|
local IPartialCommit = 15 -- update top choice to current position and jump
|
||||||
|
local IBackCommit = 16 -- "fails" but jump to its own 'offset'
|
||||||
|
local IFailTwice = 17 -- pop one choice and then fail
|
||||||
|
local IFail = 18 -- go back to saved state on choice and jump to saved offset
|
||||||
|
local IGiveup = 19 -- internal use
|
||||||
|
local IFullCapture = 20 -- complete capture of last 'off' chars
|
||||||
|
local IOpenCapture = 21 -- start a capture
|
||||||
|
local ICloseCapture = 22
|
||||||
|
local ICloseRunTime = 23
|
||||||
|
|
||||||
|
local Cclose = 0
|
||||||
|
local Cposition = 1
|
||||||
|
local Cconst = 2
|
||||||
|
local Cbackref = 3
|
||||||
|
local Carg = 4
|
||||||
|
local Csimple = 5
|
||||||
|
local Ctable = 6
|
||||||
|
local Cfunction = 7
|
||||||
|
local Cquery = 8
|
||||||
|
local Cstring = 9
|
||||||
|
local Cnum = 10
|
||||||
|
local Csubst = 11
|
||||||
|
local Cfold = 12
|
||||||
|
local Cruntime = 13
|
||||||
|
local Cgroup = 14
|
||||||
|
|
||||||
|
|
||||||
|
-- number of siblings for each tree
|
||||||
|
local numsiblings = {
|
||||||
|
[TRep] = 1,
|
||||||
|
[TSeq] = 2,
|
||||||
|
[TChoice] = 2,
|
||||||
|
[TNot] = 1,
|
||||||
|
[TAnd] = 1,
|
||||||
|
[TRule] = 2,
|
||||||
|
[TGrammar] = 1,
|
||||||
|
[TBehind] = 1,
|
||||||
|
[TCapture] = 1,
|
||||||
|
[TRunTime] = 1,
|
||||||
|
}
|
||||||
|
local names = {
|
||||||
|
[IAny] = "any",
|
||||||
|
[IChar] = "char",
|
||||||
|
[ISet] = "set",
|
||||||
|
[ITestAny] = "testany",
|
||||||
|
[ITestChar] = "testchar",
|
||||||
|
[ITestSet] = "testset",
|
||||||
|
[ISpan] = "span",
|
||||||
|
[IBehind] = "behind",
|
||||||
|
[IRet] = "ret",
|
||||||
|
[IEnd] = "end",
|
||||||
|
[IChoice] = "choice",
|
||||||
|
[IJmp] = "jmp",
|
||||||
|
[ICall] = "call",
|
||||||
|
[IOpenCall] = "open_call",
|
||||||
|
[ICommit] = "commit",
|
||||||
|
[IPartialCommit] = "partial_commit",
|
||||||
|
[IBackCommit] = "back_commit",
|
||||||
|
[IFailTwice] = "failtwice",
|
||||||
|
[IFail] = "fail",
|
||||||
|
[IGiveup] = "giveup",
|
||||||
|
[IFullCapture] = "fullcapture",
|
||||||
|
[IOpenCapture] = "opencapture",
|
||||||
|
[ICloseCapture] = "closecapture",
|
||||||
|
[ICloseRunTime] = "closeruntime"
|
||||||
|
}
|
||||||
|
|
||||||
|
local function printcharset(st)
|
||||||
|
io.write("[");
|
||||||
|
local i = 0
|
||||||
|
while i <= 255 do
|
||||||
|
local first = i;
|
||||||
|
while band(st[rshift(i, 5)], lshift(1, band(i, 31))) ~= 0 and i <= 255 do
|
||||||
|
i = i + 1
|
||||||
|
end
|
||||||
|
if i - 1 == first then -- unary range?
|
||||||
|
io.write(("(%02x)"):format(first))
|
||||||
|
elseif i - 1 > first then -- non-empty range?
|
||||||
|
io.write(("(%02x-%02x)"):format(first, i - 1))
|
||||||
|
end
|
||||||
|
i = i + 1
|
||||||
|
end
|
||||||
|
io.write("]")
|
||||||
|
end
|
||||||
|
|
||||||
|
local modes = {
|
||||||
|
[Cclose] = "close",
|
||||||
|
[Cposition] = "position",
|
||||||
|
[Cconst] = "constant",
|
||||||
|
[Cbackref] = "backref",
|
||||||
|
[Carg] = "argument",
|
||||||
|
[Csimple] = "simple",
|
||||||
|
[Ctable] = "table",
|
||||||
|
[Cfunction] = "function",
|
||||||
|
[Cquery] = "query",
|
||||||
|
[Cstring] = "string",
|
||||||
|
[Cnum] = "num",
|
||||||
|
[Csubst] = "substitution",
|
||||||
|
[Cfold] = "fold",
|
||||||
|
[Cruntime] = "runtime",
|
||||||
|
[Cgroup] = "group"
|
||||||
|
}
|
||||||
|
|
||||||
|
local function printcapkind(kind)
|
||||||
|
io.write(("%s"):format(modes[kind]))
|
||||||
|
end
|
||||||
|
|
||||||
|
local function printjmp(p, index)
|
||||||
|
io.write(("-> %d"):format(index + p[index].offset))
|
||||||
|
end
|
||||||
|
|
||||||
|
local function printrulename(p, index, rulenames)
|
||||||
|
if rulenames and rulenames[index + p[index].offset] then
|
||||||
|
io.write(' ', rulenames[index + p[index].offset])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function printinst(p, index, valuetable, rulenames)
|
||||||
|
local code = p[index].code
|
||||||
|
if rulenames and rulenames[index] then
|
||||||
|
io.write(rulenames[index], '\n')
|
||||||
|
end
|
||||||
|
io.write(("%04d: %s "):format(index, names[code]))
|
||||||
|
if code == IChar then
|
||||||
|
io.write(("'%s'"):format(string.char(p[index].val)))
|
||||||
|
elseif code == ITestChar then
|
||||||
|
io.write(("'%s'"):format(string.char(p[index].val)))
|
||||||
|
printjmp(p, index)
|
||||||
|
printrulename(p, index, rulenames)
|
||||||
|
elseif code == IFullCapture then
|
||||||
|
printcapkind(band(p[index].val, 0x0f));
|
||||||
|
io.write((" (size = %d) (idx = %s)"):format(band(rshift(p[index].val, 4), 0xF), tostring(valuetable[p[index].offset])))
|
||||||
|
elseif code == IOpenCapture then
|
||||||
|
printcapkind(band(p[index].val, 0x0f))
|
||||||
|
io.write((" (idx = %s)"):format(tostring(valuetable[p[index].offset])))
|
||||||
|
elseif code == ISet then
|
||||||
|
printcharset(valuetable[p[index].val]);
|
||||||
|
elseif code == ITestSet then
|
||||||
|
printcharset(valuetable[p[index].val])
|
||||||
|
printjmp(p, index);
|
||||||
|
printrulename(p, index, rulenames)
|
||||||
|
elseif code == ISpan then
|
||||||
|
printcharset(valuetable[p[index].val]);
|
||||||
|
elseif code == IOpenCall then
|
||||||
|
io.write(("-> %d"):format(p[index].offset))
|
||||||
|
elseif code == IBehind then
|
||||||
|
io.write(("%d"):format(p[index].val))
|
||||||
|
elseif code == IJmp or code == ICall or code == ICommit or code == IChoice or
|
||||||
|
code == IPartialCommit or code == IBackCommit or code == ITestAny then
|
||||||
|
printjmp(p, index);
|
||||||
|
if (code == ICall or code == IJmp) and p[index].aux > 0 then
|
||||||
|
io.write(' ', valuetable[p[index].aux])
|
||||||
|
else
|
||||||
|
printrulename(p, index, rulenames)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
io.write("\n")
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local function printpatt(p, valuetable)
|
||||||
|
local ruleNames = {}
|
||||||
|
for i = 0, p.size - 1 do
|
||||||
|
local code = p.p[i].code
|
||||||
|
if (code == ICall or code == IJmp) and p.p[i].aux > 0 then
|
||||||
|
local index = i + p.p[i].offset
|
||||||
|
ruleNames[index] = valuetable[p.p[i].aux]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
for i = 0, p.size - 1 do
|
||||||
|
printinst(p.p, i, valuetable, ruleNames)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local function printcap(cap, index, valuetable)
|
||||||
|
printcapkind(cap[index].kind)
|
||||||
|
io.write((" (idx: %s - size: %d) -> %d\n"):format(valuetable[cap[index].idx], cap[index].siz, cap[index].s))
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local function printcaplist(cap, limit, valuetable)
|
||||||
|
io.write(">======\n")
|
||||||
|
local index = 0
|
||||||
|
while cap[index].s and index < limit do
|
||||||
|
printcap(cap, index, valuetable)
|
||||||
|
index = index + 1
|
||||||
|
end
|
||||||
|
io.write("=======\n")
|
||||||
|
end
|
||||||
|
|
||||||
|
-- ======================================================
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-- {======================================================
|
||||||
|
-- Printing trees (for debugging)
|
||||||
|
-- =======================================================
|
||||||
|
|
||||||
|
local tagnames = {
|
||||||
|
[TChar] = "char",
|
||||||
|
[TSet] = "set",
|
||||||
|
[TAny] = "any",
|
||||||
|
[TTrue] = "true",
|
||||||
|
[TFalse] = "false",
|
||||||
|
[TRep] = "rep",
|
||||||
|
[TSeq] = "seq",
|
||||||
|
[TChoice] = "choice",
|
||||||
|
[TNot] = "not",
|
||||||
|
[TAnd] = "and",
|
||||||
|
[TCall] = "call",
|
||||||
|
[TOpenCall] = "opencall",
|
||||||
|
[TRule] = "rule",
|
||||||
|
[TGrammar] = "grammar",
|
||||||
|
[TBehind] = "behind",
|
||||||
|
[TCapture] = "capture",
|
||||||
|
[TRunTime] = "run-time"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
local function printtree(tree, ident, index, valuetable)
|
||||||
|
for i = 1, ident do
|
||||||
|
io.write(" ")
|
||||||
|
end
|
||||||
|
local tag = tree[index].tag
|
||||||
|
io.write(("%s"):format(tagnames[tag]))
|
||||||
|
if tag == TChar then
|
||||||
|
local c = tree[index].val
|
||||||
|
if ffi.C.isprint(c) then
|
||||||
|
io.write((" '%c'\n"):format(c))
|
||||||
|
else
|
||||||
|
io.write((" (%02X)\n"):format(c))
|
||||||
|
end
|
||||||
|
elseif tag == TSet then
|
||||||
|
printcharset(valuetable[tree[index].val]);
|
||||||
|
io.write("\n")
|
||||||
|
elseif tag == TOpenCall or tag == TCall then
|
||||||
|
io.write((" key: %s\n"):format(tostring(valuetable[tree[index].val])))
|
||||||
|
elseif tag == TBehind then
|
||||||
|
io.write((" %d\n"):format(tree[index].val))
|
||||||
|
printtree(tree, ident + 2, index + 1, valuetable);
|
||||||
|
elseif tag == TCapture then
|
||||||
|
io.write((" cap: %s n: %s\n"):format(modes[bit.band(tree[index].cap, 0xffff)], valuetable[tree[index].val]))
|
||||||
|
printtree(tree, ident + 2, index + 1, valuetable);
|
||||||
|
elseif tag == TRule then
|
||||||
|
local extra = bit.band(tree[index].cap, RuleLR) == RuleLR and ' left recursive' or ''
|
||||||
|
extra = extra .. (bit.band(tree[index].cap, Ruleused) ~= Ruleused and ' not used' or '')
|
||||||
|
io.write((" n: %d key: %s%s\n"):format(bit.band(tree[index].cap, 0xffff) - 1, valuetable[tree[index].val], extra))
|
||||||
|
printtree(tree, ident + 2, index + 1, valuetable);
|
||||||
|
-- do not print next rule as a sibling
|
||||||
|
elseif tag == TGrammar then
|
||||||
|
local ruleindex = index + 1
|
||||||
|
io.write((" %d\n"):format(tree[index].val)) -- number of rules
|
||||||
|
for i = 1, tree[index].val do
|
||||||
|
printtree(tree, ident + 2, ruleindex, valuetable);
|
||||||
|
ruleindex = ruleindex + tree[ruleindex].ps
|
||||||
|
end
|
||||||
|
assert(tree[ruleindex].tag == TTrue); -- sentinel
|
||||||
|
else
|
||||||
|
local sibs = numsiblings[tree[index].tag] or 0
|
||||||
|
io.write("\n")
|
||||||
|
if sibs >= 1 then
|
||||||
|
printtree(tree, ident + 2, index + 1, valuetable);
|
||||||
|
if sibs >= 2 then
|
||||||
|
printtree(tree, ident + 2, index + tree[index].ps, valuetable)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- }====================================================== */
|
||||||
|
|
||||||
|
return {
|
||||||
|
printtree = printtree,
|
||||||
|
printpatt = printpatt,
|
||||||
|
printcaplist = printcaplist,
|
||||||
|
printinst = printinst
|
||||||
|
}
|
1041
tools/lpeg/lpvm.lua
Normal file
1041
tools/lpeg/lpvm.lua
Normal file
File diff suppressed because it is too large
Load Diff
286
tools/lpeg/re.lua
Normal file
286
tools/lpeg/re.lua
Normal file
@ -0,0 +1,286 @@
|
|||||||
|
-- $Id: re.lua,v 1.44 2013/03/26 20:11:40 roberto Exp $
|
||||||
|
-- 2014/08/15 changes rostislav
|
||||||
|
|
||||||
|
-- imported functions and modules
|
||||||
|
local tonumber, print, error = tonumber, print, error
|
||||||
|
local setmetatable = setmetatable
|
||||||
|
local m = require"lpeglj"
|
||||||
|
|
||||||
|
-- 'm' will be used to parse expressions, and 'mm' will be used to
|
||||||
|
-- create expressions; that is, 're' runs on 'm', creating patterns
|
||||||
|
-- on 'mm'
|
||||||
|
local mm = m
|
||||||
|
|
||||||
|
-- pattern's metatable
|
||||||
|
local mt = getmetatable(mm.P(0))
|
||||||
|
mt = m.version() == "1.0.0.0LJ" and m or mt
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-- No more global accesses after this point
|
||||||
|
local version = _VERSION
|
||||||
|
if version == "Lua 5.2" then _ENV = nil end
|
||||||
|
|
||||||
|
|
||||||
|
local any = m.P(1)
|
||||||
|
|
||||||
|
|
||||||
|
-- Pre-defined names
|
||||||
|
local Predef = { nl = m.P"\n" }
|
||||||
|
|
||||||
|
|
||||||
|
local mem
|
||||||
|
local fmem
|
||||||
|
local gmem
|
||||||
|
|
||||||
|
|
||||||
|
local function updatelocale ()
|
||||||
|
mm.locale(Predef)
|
||||||
|
Predef.a = Predef.alpha
|
||||||
|
Predef.c = Predef.cntrl
|
||||||
|
Predef.d = Predef.digit
|
||||||
|
Predef.g = Predef.graph
|
||||||
|
Predef.l = Predef.lower
|
||||||
|
Predef.p = Predef.punct
|
||||||
|
Predef.s = Predef.space
|
||||||
|
Predef.u = Predef.upper
|
||||||
|
Predef.w = Predef.alnum
|
||||||
|
Predef.x = Predef.xdigit
|
||||||
|
Predef.A = any - Predef.a
|
||||||
|
Predef.C = any - Predef.c
|
||||||
|
Predef.D = any - Predef.d
|
||||||
|
Predef.G = any - Predef.g
|
||||||
|
Predef.L = any - Predef.l
|
||||||
|
Predef.P = any - Predef.p
|
||||||
|
Predef.S = any - Predef.s
|
||||||
|
Predef.U = any - Predef.u
|
||||||
|
Predef.W = any - Predef.w
|
||||||
|
Predef.X = any - Predef.x
|
||||||
|
mem = {} -- restart memoization
|
||||||
|
fmem = {}
|
||||||
|
gmem = {}
|
||||||
|
local mt = {__mode = "v"}
|
||||||
|
setmetatable(mem, mt)
|
||||||
|
setmetatable(fmem, mt)
|
||||||
|
setmetatable(gmem, mt)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
updatelocale()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
local I = m.P(function (s,i) print(i, s:sub(1, i-1)); return i end)
|
||||||
|
|
||||||
|
|
||||||
|
local function getdef (id, defs)
|
||||||
|
local c = defs and defs[id]
|
||||||
|
if not c then error("undefined name: " .. id) end
|
||||||
|
return c
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local function patt_error (s, i)
|
||||||
|
local msg = (#s < i + 20) and s:sub(i)
|
||||||
|
or s:sub(i,i+20) .. "..."
|
||||||
|
msg = ("pattern error near '%s'"):format(msg)
|
||||||
|
error(msg, 2)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function mult (p, n)
|
||||||
|
local np = mm.P(true)
|
||||||
|
while n >= 1 do
|
||||||
|
if n%2 >= 1 then np = np * p end
|
||||||
|
p = p * p
|
||||||
|
n = n/2
|
||||||
|
end
|
||||||
|
return np
|
||||||
|
end
|
||||||
|
|
||||||
|
local function equalcap (s, i, c)
|
||||||
|
if type(c) ~= "string" then return nil end
|
||||||
|
local e = #c + i
|
||||||
|
if type(s) == 'function' then -- stream mode
|
||||||
|
if s(i, e - 1) == c then return e else return nil end
|
||||||
|
else
|
||||||
|
if s:sub(i, e - 1) == c then return e else return nil end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local S = (Predef.space + "--" * (any - Predef.nl)^0)^0
|
||||||
|
|
||||||
|
local name = m.R("AZ", "az", "__") * m.R("AZ", "az", "__", "09")^0
|
||||||
|
|
||||||
|
local arrow = S * "<-"
|
||||||
|
|
||||||
|
local seq_follow = m.P"/" + ")" + "}" + ":}" + "~}" + "|}" + (name * arrow) + -1
|
||||||
|
|
||||||
|
name = m.C(name)
|
||||||
|
|
||||||
|
|
||||||
|
-- a defined name only have meaning in a given environment
|
||||||
|
local Def = name * m.Carg(1)
|
||||||
|
|
||||||
|
local num = m.C(m.R"09"^1) * S / tonumber
|
||||||
|
|
||||||
|
local String = "'" * m.C((any - "'")^0) * "'" +
|
||||||
|
'"' * m.C((any - '"')^0) * '"'
|
||||||
|
|
||||||
|
|
||||||
|
local defined = "%" * Def / function (c,Defs)
|
||||||
|
local cat = Defs and Defs[c] or Predef[c]
|
||||||
|
if not cat then error ("name '" .. c .. "' undefined") end
|
||||||
|
return cat
|
||||||
|
end
|
||||||
|
|
||||||
|
local Range = m.Cs(any * (m.P"-"/"") * (any - "]")) / mm.R
|
||||||
|
|
||||||
|
local item = defined + Range + m.C(any)
|
||||||
|
|
||||||
|
local Class =
|
||||||
|
"["
|
||||||
|
* (m.C(m.P"^"^-1)) -- optional complement symbol
|
||||||
|
* m.Cf(item * (item - "]")^0, mt.__add) /
|
||||||
|
function (c, p) return c == "^" and any - p or p end
|
||||||
|
* "]"
|
||||||
|
|
||||||
|
local function adddef (t, k, exp)
|
||||||
|
if t[k] then
|
||||||
|
error("'"..k.."' already defined as a rule")
|
||||||
|
else
|
||||||
|
t[k] = exp
|
||||||
|
end
|
||||||
|
return t
|
||||||
|
end
|
||||||
|
|
||||||
|
local function firstdef (n, r) return adddef({n}, n, r) end
|
||||||
|
|
||||||
|
|
||||||
|
local function NT (n, b, p)
|
||||||
|
if not b then
|
||||||
|
error("rule '"..n.."' used outside a grammar")
|
||||||
|
else return mm.V(n, p or 0)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local exp = m.P{ "Exp",
|
||||||
|
Exp = S * ( m.V"Grammar"
|
||||||
|
+ m.Cf(m.V"Seq" * ("/" * S * m.V"Seq")^0, mt.__add) );
|
||||||
|
Seq = m.Cf(m.Cc(m.P"") * m.V"Prefix"^0 , mt.__mul)
|
||||||
|
* (#seq_follow + patt_error);
|
||||||
|
Prefix = "&" * S * m.V"Prefix" / mt.__len
|
||||||
|
+ "!" * S * m.V"Prefix" / mt.__unm
|
||||||
|
+ m.V"Suffix";
|
||||||
|
Suffix = m.Cf(m.V"Primary" * S *
|
||||||
|
( ( m.P"+" * m.Cc(1, mt.__pow)
|
||||||
|
+ m.P"*" * m.Cc(0, mt.__pow)
|
||||||
|
+ m.P"?" * m.Cc(-1, mt.__pow)
|
||||||
|
+ "^" * ( m.Cg(num * m.Cc(mult))
|
||||||
|
+ m.Cg(m.C(m.S"+-" * m.R"09"^1) * m.Cc(mt.__pow))
|
||||||
|
)
|
||||||
|
+ "->" * S * ( m.Cg((String + num) * m.Cc(mt.__div))
|
||||||
|
+ m.P"{}" * m.Cc(nil, m.Ct)
|
||||||
|
+ m.Cg(Def / getdef * m.Cc(mt.__div))
|
||||||
|
)
|
||||||
|
+ "=>" * S * m.Cg(Def / getdef * m.Cc(m.Cmt))
|
||||||
|
) * S
|
||||||
|
)^0, function (a,b,f) return f(a,b) end );
|
||||||
|
Primary = "(" * m.V"Exp" * ")"
|
||||||
|
+ String / mm.P
|
||||||
|
+ Class
|
||||||
|
+ defined
|
||||||
|
+ "{:" * (name * ":" + m.Cc(nil)) * m.V"Exp" * ":}" /
|
||||||
|
function (n, p) return mm.Cg(p, n) end
|
||||||
|
+ "=" * name / function (n) return mm.Cmt(mm.Cb(n), equalcap) end
|
||||||
|
+ m.P"{}" / mm.Cp
|
||||||
|
+ "{~" * m.V"Exp" * "~}" / mm.Cs
|
||||||
|
+ "{|" * m.V"Exp" * "|}" / mm.Ct
|
||||||
|
+ "{" * m.V"Exp" * "}" / mm.C
|
||||||
|
+ m.P"." * m.Cc(any)
|
||||||
|
+ (name * m.Cb("G") * (S * ":" * S * num)^-1 * -arrow + "<" * name * m.Cb("G") * (S * ":" * S * num)^-1 * ">") / NT;
|
||||||
|
Definition = name * arrow * m.V"Exp";
|
||||||
|
Grammar = m.Cg(m.Cc(true), "G") *
|
||||||
|
m.Cf(m.V"Definition" / firstdef * m.Cg(m.V"Definition")^0,
|
||||||
|
adddef) / mm.P
|
||||||
|
}
|
||||||
|
|
||||||
|
local pattern = S * m.Cg(m.Cc(false), "G") * exp / mm.P * (-any + patt_error)
|
||||||
|
|
||||||
|
|
||||||
|
local function compile (p, defs)
|
||||||
|
if mm.type(p) == "pattern" then return p end -- already compiled
|
||||||
|
local cp = pattern:match(p, 1, defs)
|
||||||
|
if not cp then error("incorrect pattern", 3) end
|
||||||
|
return cp
|
||||||
|
end
|
||||||
|
|
||||||
|
local function match (s, p, i)
|
||||||
|
local cp = mem[p]
|
||||||
|
if not cp then
|
||||||
|
cp = compile(p)
|
||||||
|
mem[p] = cp
|
||||||
|
end
|
||||||
|
return cp:match(s, i or 1)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function streammatch (p, i)
|
||||||
|
local cp = mem[p]
|
||||||
|
if not cp then
|
||||||
|
cp = compile(p)
|
||||||
|
mem[p] = cp
|
||||||
|
end
|
||||||
|
return cp:streammatch(i or 1)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Only for testing purpose
|
||||||
|
local function emulatestreammatch(s, p, i)
|
||||||
|
local cp = mem[p]
|
||||||
|
if not cp then
|
||||||
|
cp = compile(p)
|
||||||
|
mem[p] = cp
|
||||||
|
end
|
||||||
|
return cp:emulatestreammatch(s, i or 1)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function find (s, p, i)
|
||||||
|
local cp = fmem[p]
|
||||||
|
if not cp then
|
||||||
|
cp = compile(p) / 0
|
||||||
|
cp = mm.P{ mm.Cp() * cp * mm.Cp() + 1 * mm.V(1) }
|
||||||
|
fmem[p] = cp
|
||||||
|
end
|
||||||
|
local i, e = cp:match(s, i or 1)
|
||||||
|
if i then return i, e - 1
|
||||||
|
else return i
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function gsub (s, p, rep)
|
||||||
|
local g = gmem[p] or {} -- ensure gmem[p] is not collected while here
|
||||||
|
gmem[p] = g
|
||||||
|
local cp = g[rep]
|
||||||
|
if not cp then
|
||||||
|
cp = compile(p)
|
||||||
|
cp = mm.Cs((cp / rep + 1)^0)
|
||||||
|
g[rep] = cp
|
||||||
|
end
|
||||||
|
return cp:match(s)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- exported names
|
||||||
|
local re = {
|
||||||
|
compile = compile,
|
||||||
|
match = match,
|
||||||
|
streammatch = streammatch,
|
||||||
|
emulatestreammatch = emulatestreammatch,
|
||||||
|
find = find,
|
||||||
|
gsub = gsub,
|
||||||
|
updatelocale = updatelocale,
|
||||||
|
}
|
||||||
|
|
||||||
|
if version == "Lua 5.1" then _G.re = re end
|
||||||
|
|
||||||
|
return re
|
25
tools/luajson/json.lua
Normal file
25
tools/luajson/json.lua
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
--[[
|
||||||
|
Licensed according to the included 'LICENSE' document
|
||||||
|
Author: Thomas Harning Jr <harningt@gmail.com>
|
||||||
|
]]
|
||||||
|
package.path = package.path .. ";lpeg/?.lua"
|
||||||
|
local decode = require("json.decode")
|
||||||
|
local encode = require("json.encode")
|
||||||
|
local util = require("json.util")
|
||||||
|
|
||||||
|
local _G = _G
|
||||||
|
|
||||||
|
local _ENV = nil
|
||||||
|
|
||||||
|
local json = {
|
||||||
|
_VERSION = "1.3.4",
|
||||||
|
_DESCRIPTION = "LuaJSON : customizable JSON decoder/encoder",
|
||||||
|
_COPYRIGHT = "Copyright (c) 2007-2014 Thomas Harning Jr. <harningt@gmail.com>",
|
||||||
|
decode = decode,
|
||||||
|
encode = encode,
|
||||||
|
util = util
|
||||||
|
}
|
||||||
|
|
||||||
|
_G.json = json
|
||||||
|
|
||||||
|
return json
|
171
tools/luajson/json/decode.lua
Normal file
171
tools/luajson/json/decode.lua
Normal file
@ -0,0 +1,171 @@
|
|||||||
|
--[[
|
||||||
|
Licensed according to the included 'LICENSE' document
|
||||||
|
Author: Thomas Harning Jr <harningt@gmail.com>
|
||||||
|
]]
|
||||||
|
local lpeg = require("lpeg")
|
||||||
|
|
||||||
|
local error = error
|
||||||
|
local pcall = pcall
|
||||||
|
|
||||||
|
local jsonutil = require("json.util")
|
||||||
|
local merge = jsonutil.merge
|
||||||
|
local util = require("json.decode.util")
|
||||||
|
|
||||||
|
local decode_state = require("json.decode.state")
|
||||||
|
|
||||||
|
local setmetatable, getmetatable = setmetatable, getmetatable
|
||||||
|
local assert = assert
|
||||||
|
local ipairs, pairs = ipairs, pairs
|
||||||
|
local string_char = require("string").char
|
||||||
|
|
||||||
|
local type = type
|
||||||
|
|
||||||
|
local require = require
|
||||||
|
|
||||||
|
local _ENV = nil
|
||||||
|
|
||||||
|
local modulesToLoad = {
|
||||||
|
"composite",
|
||||||
|
"strings",
|
||||||
|
"number",
|
||||||
|
"others"
|
||||||
|
}
|
||||||
|
local loadedModules = {
|
||||||
|
}
|
||||||
|
|
||||||
|
local json_decode = {}
|
||||||
|
|
||||||
|
json_decode.default = {
|
||||||
|
unicodeWhitespace = true,
|
||||||
|
initialObject = false,
|
||||||
|
nothrow = false
|
||||||
|
}
|
||||||
|
|
||||||
|
local modes_defined = { "default", "strict", "simple" }
|
||||||
|
|
||||||
|
json_decode.simple = {}
|
||||||
|
|
||||||
|
json_decode.strict = {
|
||||||
|
unicodeWhitespace = true,
|
||||||
|
initialObject = true,
|
||||||
|
nothrow = false
|
||||||
|
}
|
||||||
|
|
||||||
|
for _,name in ipairs(modulesToLoad) do
|
||||||
|
local mod = require("json.decode." .. name)
|
||||||
|
if mod.mergeOptions then
|
||||||
|
for _, mode in pairs(modes_defined) do
|
||||||
|
mod.mergeOptions(json_decode[mode], mode)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
loadedModules[#loadedModules + 1] = mod
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Shift over default into defaultOptions to permit build optimization
|
||||||
|
local defaultOptions = json_decode.default
|
||||||
|
json_decode.default = nil
|
||||||
|
|
||||||
|
local function generateDecoder(lexer, options)
|
||||||
|
-- Marker to permit detection of final end
|
||||||
|
local marker = {}
|
||||||
|
local parser = lpeg.Ct((options.ignored * lexer)^0 * lpeg.Cc(marker)) * options.ignored * (lpeg.P(-1) + util.unexpected())
|
||||||
|
local decoder = function(data)
|
||||||
|
local state = decode_state.create(options)
|
||||||
|
local parsed = parser:match(data)
|
||||||
|
assert(parsed, "Invalid JSON data")
|
||||||
|
local i = 0
|
||||||
|
while true do
|
||||||
|
i = i + 1
|
||||||
|
local item = parsed[i]
|
||||||
|
if item == marker then break end
|
||||||
|
if type(item) == 'function' and item ~= jsonutil.undefined and item ~= jsonutil.null then
|
||||||
|
item(state)
|
||||||
|
else
|
||||||
|
state:set_value(item)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if options.initialObject then
|
||||||
|
assert(type(state.previous) == 'table', "Initial value not an object or array")
|
||||||
|
end
|
||||||
|
-- Make sure stack is empty
|
||||||
|
assert(state.i == 0, "Unclosed elements present")
|
||||||
|
return state.previous
|
||||||
|
end
|
||||||
|
if options.nothrow then
|
||||||
|
return function(data)
|
||||||
|
local status, rv = pcall(decoder, data)
|
||||||
|
if status then
|
||||||
|
return rv
|
||||||
|
else
|
||||||
|
return nil, rv
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return decoder
|
||||||
|
end
|
||||||
|
|
||||||
|
local function buildDecoder(mode)
|
||||||
|
mode = mode and merge({}, defaultOptions, mode) or defaultOptions
|
||||||
|
for _, mod in ipairs(loadedModules) do
|
||||||
|
if mod.mergeOptions then
|
||||||
|
mod.mergeOptions(mode)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
local ignored = mode.unicodeWhitespace and util.unicode_ignored or util.ascii_ignored
|
||||||
|
-- Store 'ignored' in the global options table
|
||||||
|
mode.ignored = ignored
|
||||||
|
|
||||||
|
--local grammar = {
|
||||||
|
-- [1] = mode.initialObject and (ignored * (object_type + array_type)) or value_type
|
||||||
|
--}
|
||||||
|
local lexer
|
||||||
|
for _, mod in ipairs(loadedModules) do
|
||||||
|
local new_lexer = mod.generateLexer(mode)
|
||||||
|
lexer = lexer and lexer + new_lexer or new_lexer
|
||||||
|
end
|
||||||
|
return generateDecoder(lexer, mode)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Since 'default' is nil, we cannot take map it
|
||||||
|
local defaultDecoder = buildDecoder(json_decode.default)
|
||||||
|
local prebuilt_decoders = {}
|
||||||
|
for _, mode in pairs(modes_defined) do
|
||||||
|
if json_decode[mode] ~= nil then
|
||||||
|
prebuilt_decoders[json_decode[mode]] = buildDecoder(json_decode[mode])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[
|
||||||
|
Options:
|
||||||
|
number => number decode options
|
||||||
|
string => string decode options
|
||||||
|
array => array decode options
|
||||||
|
object => object decode options
|
||||||
|
initialObject => whether or not to require the initial object to be a table/array
|
||||||
|
allowUndefined => whether or not to allow undefined values
|
||||||
|
]]
|
||||||
|
local function getDecoder(mode)
|
||||||
|
mode = mode == true and json_decode.strict or mode or json_decode.default
|
||||||
|
local decoder = mode == nil and defaultDecoder or prebuilt_decoders[mode]
|
||||||
|
if decoder then
|
||||||
|
return decoder
|
||||||
|
end
|
||||||
|
return buildDecoder(mode)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function decode(data, mode)
|
||||||
|
local decoder = getDecoder(mode)
|
||||||
|
return decoder(data)
|
||||||
|
end
|
||||||
|
|
||||||
|
local mt = {}
|
||||||
|
mt.__call = function(self, ...)
|
||||||
|
return decode(...)
|
||||||
|
end
|
||||||
|
|
||||||
|
json_decode.getDecoder = getDecoder
|
||||||
|
json_decode.decode = decode
|
||||||
|
json_decode.util = util
|
||||||
|
setmetatable(json_decode, mt)
|
||||||
|
|
||||||
|
return json_decode
|
190
tools/luajson/json/decode/composite.lua
Normal file
190
tools/luajson/json/decode/composite.lua
Normal file
@ -0,0 +1,190 @@
|
|||||||
|
--[[
|
||||||
|
Licensed according to the included 'LICENSE' document
|
||||||
|
Author: Thomas Harning Jr <harningt@gmail.com>
|
||||||
|
]]
|
||||||
|
local pairs = pairs
|
||||||
|
local type = type
|
||||||
|
|
||||||
|
local lpeg = require("lpeg")
|
||||||
|
|
||||||
|
local util = require("json.decode.util")
|
||||||
|
local jsonutil = require("json.util")
|
||||||
|
|
||||||
|
local rawset = rawset
|
||||||
|
|
||||||
|
local assert = assert
|
||||||
|
local tostring = tostring
|
||||||
|
|
||||||
|
local error = error
|
||||||
|
local getmetatable = getmetatable
|
||||||
|
|
||||||
|
local _ENV = nil
|
||||||
|
|
||||||
|
local defaultOptions = {
|
||||||
|
array = {
|
||||||
|
trailingComma = true
|
||||||
|
},
|
||||||
|
object = {
|
||||||
|
trailingComma = true,
|
||||||
|
number = true,
|
||||||
|
identifier = true,
|
||||||
|
setObjectKey = rawset
|
||||||
|
},
|
||||||
|
calls = {
|
||||||
|
defs = nil,
|
||||||
|
-- By default, do not allow undefined calls to be de-serialized as call objects
|
||||||
|
allowUndefined = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
local modeOptions = {
|
||||||
|
default = nil,
|
||||||
|
strict = {
|
||||||
|
array = {
|
||||||
|
trailingComma = false
|
||||||
|
},
|
||||||
|
object = {
|
||||||
|
trailingComma = false,
|
||||||
|
number = false,
|
||||||
|
identifier = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
local function BEGIN_ARRAY(state)
|
||||||
|
state:push()
|
||||||
|
state:new_array()
|
||||||
|
end
|
||||||
|
local function END_ARRAY(state)
|
||||||
|
state:end_array()
|
||||||
|
state:pop()
|
||||||
|
end
|
||||||
|
|
||||||
|
local function BEGIN_OBJECT(state)
|
||||||
|
state:push()
|
||||||
|
state:new_object()
|
||||||
|
end
|
||||||
|
local function END_OBJECT(state)
|
||||||
|
state:end_object()
|
||||||
|
state:pop()
|
||||||
|
end
|
||||||
|
|
||||||
|
local function END_CALL(state)
|
||||||
|
state:end_call()
|
||||||
|
state:pop()
|
||||||
|
end
|
||||||
|
|
||||||
|
local function SET_KEY(state)
|
||||||
|
state:set_key()
|
||||||
|
end
|
||||||
|
|
||||||
|
local function NEXT_VALUE(state)
|
||||||
|
state:put_value()
|
||||||
|
end
|
||||||
|
|
||||||
|
local function mergeOptions(options, mode)
|
||||||
|
jsonutil.doOptionMerge(options, true, 'array', defaultOptions, mode and modeOptions[mode])
|
||||||
|
jsonutil.doOptionMerge(options, true, 'object', defaultOptions, mode and modeOptions[mode])
|
||||||
|
jsonutil.doOptionMerge(options, true, 'calls', defaultOptions, mode and modeOptions[mode])
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local isPattern
|
||||||
|
if lpeg.type then
|
||||||
|
function isPattern(value)
|
||||||
|
return lpeg.type(value) == 'pattern'
|
||||||
|
end
|
||||||
|
else
|
||||||
|
local metaAdd = getmetatable(lpeg.P("")).__add
|
||||||
|
function isPattern(value)
|
||||||
|
return getmetatable(value).__add == metaAdd
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local function generateSingleCallLexer(name, func)
|
||||||
|
if type(name) ~= 'string' and not isPattern(name) then
|
||||||
|
error("Invalid functionCalls name: " .. tostring(name) .. " not a string or LPEG pattern")
|
||||||
|
end
|
||||||
|
-- Allow boolean or function to match up w/ encoding permissions
|
||||||
|
if type(func) ~= 'boolean' and type(func) ~= 'function' then
|
||||||
|
error("Invalid functionCalls item: " .. name .. " not a function")
|
||||||
|
end
|
||||||
|
local function buildCallCapture(name)
|
||||||
|
return function(state)
|
||||||
|
if func == false then
|
||||||
|
error("Function call on '" .. name .. "' not permitted")
|
||||||
|
end
|
||||||
|
state:push()
|
||||||
|
state:new_call(name, func)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
local nameCallCapture
|
||||||
|
if type(name) == 'string' then
|
||||||
|
nameCallCapture = lpeg.P(name .. "(") * lpeg.Cc(name) / buildCallCapture
|
||||||
|
else
|
||||||
|
-- Name matcher expected to produce a capture
|
||||||
|
nameCallCapture = name * "(" / buildCallCapture
|
||||||
|
end
|
||||||
|
-- Call func over nameCallCapture and value to permit function receiving name
|
||||||
|
return nameCallCapture
|
||||||
|
end
|
||||||
|
|
||||||
|
local function generateNamedCallLexers(options)
|
||||||
|
if not options.calls or not options.calls.defs then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
local callCapture
|
||||||
|
for name, func in pairs(options.calls.defs) do
|
||||||
|
local newCapture = generateSingleCallLexer(name, func)
|
||||||
|
if not callCapture then
|
||||||
|
callCapture = newCapture
|
||||||
|
else
|
||||||
|
callCapture = callCapture + newCapture
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return callCapture
|
||||||
|
end
|
||||||
|
|
||||||
|
local function generateCallLexer(options)
|
||||||
|
local lexer
|
||||||
|
local namedCapture = generateNamedCallLexers(options)
|
||||||
|
if options.calls and options.calls.allowUndefined then
|
||||||
|
lexer = generateSingleCallLexer(lpeg.C(util.identifier), true)
|
||||||
|
end
|
||||||
|
if namedCapture then
|
||||||
|
lexer = lexer and lexer + namedCapture or namedCapture
|
||||||
|
end
|
||||||
|
if lexer then
|
||||||
|
lexer = lexer + lpeg.P(")") * lpeg.Cc(END_CALL)
|
||||||
|
end
|
||||||
|
return lexer
|
||||||
|
end
|
||||||
|
|
||||||
|
local function generateLexer(options)
|
||||||
|
local ignored = options.ignored
|
||||||
|
local array_options, object_options = options.array, options.object
|
||||||
|
local lexer =
|
||||||
|
lpeg.P("[") * lpeg.Cc(BEGIN_ARRAY)
|
||||||
|
+ lpeg.P("]") * lpeg.Cc(END_ARRAY)
|
||||||
|
+ lpeg.P("{") * lpeg.Cc(BEGIN_OBJECT)
|
||||||
|
+ lpeg.P("}") * lpeg.Cc(END_OBJECT)
|
||||||
|
+ lpeg.P(":") * lpeg.Cc(SET_KEY)
|
||||||
|
+ lpeg.P(",") * lpeg.Cc(NEXT_VALUE)
|
||||||
|
if object_options.identifier then
|
||||||
|
-- Add identifier match w/ validation check that it is in key
|
||||||
|
lexer = lexer + lpeg.C(util.identifier) * ignored * lpeg.P(":") * lpeg.Cc(SET_KEY)
|
||||||
|
end
|
||||||
|
local callLexers = generateCallLexer(options)
|
||||||
|
if callLexers then
|
||||||
|
lexer = lexer + callLexers
|
||||||
|
end
|
||||||
|
return lexer
|
||||||
|
end
|
||||||
|
|
||||||
|
local composite = {
|
||||||
|
mergeOptions = mergeOptions,
|
||||||
|
generateLexer = generateLexer
|
||||||
|
}
|
||||||
|
|
||||||
|
return composite
|
100
tools/luajson/json/decode/number.lua
Normal file
100
tools/luajson/json/decode/number.lua
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
--[[
|
||||||
|
Licensed according to the included 'LICENSE' document
|
||||||
|
Author: Thomas Harning Jr <harningt@gmail.com>
|
||||||
|
]]
|
||||||
|
local lpeg = require("lpeg")
|
||||||
|
local tonumber = tonumber
|
||||||
|
local jsonutil = require("json.util")
|
||||||
|
local merge = jsonutil.merge
|
||||||
|
local util = require("json.decode.util")
|
||||||
|
|
||||||
|
local _ENV = nil
|
||||||
|
|
||||||
|
local digit = lpeg.R("09")
|
||||||
|
local digits = digit^1
|
||||||
|
|
||||||
|
-- Illegal octal declaration
|
||||||
|
local illegal_octal_detect = #(lpeg.P('0') * digits) * util.denied("Octal numbers")
|
||||||
|
|
||||||
|
local int = (lpeg.P('-') + 0) * (lpeg.R("19") * digits + illegal_octal_detect + digit)
|
||||||
|
|
||||||
|
local frac = lpeg.P('.') * digits
|
||||||
|
|
||||||
|
local exp = lpeg.S("Ee") * (lpeg.S("-+") + 0) * digits
|
||||||
|
|
||||||
|
local nan = lpeg.S("Nn") * lpeg.S("Aa") * lpeg.S("Nn")
|
||||||
|
local inf = lpeg.S("Ii") * lpeg.P("nfinity")
|
||||||
|
local ninf = lpeg.P('-') * lpeg.S("Ii") * lpeg.P("nfinity")
|
||||||
|
local hex = (lpeg.P("0x") + lpeg.P("0X")) * lpeg.R("09","AF","af")^1
|
||||||
|
|
||||||
|
local defaultOptions = {
|
||||||
|
nan = true,
|
||||||
|
inf = true,
|
||||||
|
frac = true,
|
||||||
|
exp = true,
|
||||||
|
hex = false
|
||||||
|
}
|
||||||
|
|
||||||
|
local modeOptions = {}
|
||||||
|
|
||||||
|
modeOptions.strict = {
|
||||||
|
nan = false,
|
||||||
|
inf = false
|
||||||
|
}
|
||||||
|
|
||||||
|
local nan_value = 0/0
|
||||||
|
local inf_value = 1/0
|
||||||
|
local ninf_value = -1/0
|
||||||
|
|
||||||
|
--[[
|
||||||
|
Options: configuration options for number rules
|
||||||
|
nan: match NaN
|
||||||
|
inf: match Infinity
|
||||||
|
frac: match fraction portion (.0)
|
||||||
|
exp: match exponent portion (e1)
|
||||||
|
DEFAULT: nan, inf, frac, exp
|
||||||
|
]]
|
||||||
|
local function mergeOptions(options, mode)
|
||||||
|
jsonutil.doOptionMerge(options, false, 'number', defaultOptions, mode and modeOptions[mode])
|
||||||
|
end
|
||||||
|
|
||||||
|
local function generateLexer(options)
|
||||||
|
options = options.number
|
||||||
|
local ret = int
|
||||||
|
if options.frac then
|
||||||
|
ret = ret * (frac + 0)
|
||||||
|
else
|
||||||
|
ret = ret * (#frac * util.denied("Fractions", "number.frac") + 0)
|
||||||
|
end
|
||||||
|
if options.exp then
|
||||||
|
ret = ret * (exp + 0)
|
||||||
|
else
|
||||||
|
ret = ret * (#exp * util.denied("Exponents", "number.exp") + 0)
|
||||||
|
end
|
||||||
|
if options.hex then
|
||||||
|
ret = hex + ret
|
||||||
|
else
|
||||||
|
ret = #hex * util.denied("Hexadecimal", "number.hex") + ret
|
||||||
|
end
|
||||||
|
-- Capture number now
|
||||||
|
ret = ret / tonumber
|
||||||
|
if options.nan then
|
||||||
|
ret = ret + nan / function() return nan_value end
|
||||||
|
else
|
||||||
|
ret = ret + #nan * util.denied("NaN", "number.nan")
|
||||||
|
end
|
||||||
|
if options.inf then
|
||||||
|
ret = ret + ninf / function() return ninf_value end + inf / function() return inf_value end
|
||||||
|
else
|
||||||
|
ret = ret + (#ninf + #inf) * util.denied("+/-Inf", "number.inf")
|
||||||
|
end
|
||||||
|
return ret
|
||||||
|
end
|
||||||
|
|
||||||
|
local number = {
|
||||||
|
int = int,
|
||||||
|
mergeOptions = mergeOptions,
|
||||||
|
generateLexer = generateLexer
|
||||||
|
}
|
||||||
|
|
||||||
|
return number
|
62
tools/luajson/json/decode/others.lua
Normal file
62
tools/luajson/json/decode/others.lua
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
--[[
|
||||||
|
Licensed according to the included 'LICENSE' document
|
||||||
|
Author: Thomas Harning Jr <harningt@gmail.com>
|
||||||
|
]]
|
||||||
|
local lpeg = require("lpeg")
|
||||||
|
local jsonutil = require("json.util")
|
||||||
|
local merge = jsonutil.merge
|
||||||
|
local util = require("json.decode.util")
|
||||||
|
|
||||||
|
-- Container module for other JavaScript types (bool, null, undefined)
|
||||||
|
|
||||||
|
local _ENV = nil
|
||||||
|
|
||||||
|
-- For null and undefined, use the util.null value to preserve null-ness
|
||||||
|
local booleanCapture =
|
||||||
|
lpeg.P("true") * lpeg.Cc(true)
|
||||||
|
+ lpeg.P("false") * lpeg.Cc(false)
|
||||||
|
|
||||||
|
local nullCapture = lpeg.P("null")
|
||||||
|
local undefinedCapture = lpeg.P("undefined")
|
||||||
|
|
||||||
|
local defaultOptions = {
|
||||||
|
allowUndefined = true,
|
||||||
|
null = jsonutil.null,
|
||||||
|
undefined = jsonutil.undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
local modeOptions = {}
|
||||||
|
|
||||||
|
modeOptions.simple = {
|
||||||
|
null = false, -- Mapped to nil
|
||||||
|
undefined = false -- Mapped to nil
|
||||||
|
}
|
||||||
|
modeOptions.strict = {
|
||||||
|
allowUndefined = false
|
||||||
|
}
|
||||||
|
|
||||||
|
local function mergeOptions(options, mode)
|
||||||
|
jsonutil.doOptionMerge(options, false, 'others', defaultOptions, mode and modeOptions[mode])
|
||||||
|
end
|
||||||
|
|
||||||
|
local function generateLexer(options)
|
||||||
|
-- The 'or nil' clause allows false to map to a nil value since 'nil' cannot be merged
|
||||||
|
options = options.others
|
||||||
|
local valueCapture = (
|
||||||
|
booleanCapture
|
||||||
|
+ nullCapture * lpeg.Cc(options.null or nil)
|
||||||
|
)
|
||||||
|
if options.allowUndefined then
|
||||||
|
valueCapture = valueCapture + undefinedCapture * lpeg.Cc(options.undefined or nil)
|
||||||
|
else
|
||||||
|
valueCapture = valueCapture + #undefinedCapture * util.denied("undefined", "others.allowUndefined")
|
||||||
|
end
|
||||||
|
return valueCapture
|
||||||
|
end
|
||||||
|
|
||||||
|
local others = {
|
||||||
|
mergeOptions = mergeOptions,
|
||||||
|
generateLexer = generateLexer
|
||||||
|
}
|
||||||
|
|
||||||
|
return others
|
189
tools/luajson/json/decode/state.lua
Normal file
189
tools/luajson/json/decode/state.lua
Normal file
@ -0,0 +1,189 @@
|
|||||||
|
--[[
|
||||||
|
Licensed according to the included 'LICENSE' document
|
||||||
|
Author: Thomas Harning Jr <harningt@gmail.com>
|
||||||
|
]]
|
||||||
|
|
||||||
|
local setmetatable = setmetatable
|
||||||
|
local jsonutil = require("json.util")
|
||||||
|
local assert = assert
|
||||||
|
local type = type
|
||||||
|
local next = next
|
||||||
|
local unpack = require("table").unpack or unpack
|
||||||
|
|
||||||
|
local _ENV = nil
|
||||||
|
|
||||||
|
local state_ops = {}
|
||||||
|
local state_mt = {
|
||||||
|
__index = state_ops
|
||||||
|
}
|
||||||
|
|
||||||
|
function state_ops.pop(self)
|
||||||
|
self.previous_set = true
|
||||||
|
self.previous = self.active
|
||||||
|
local i = self.i
|
||||||
|
-- Load in this array into the active item
|
||||||
|
self.active = self.stack[i]
|
||||||
|
self.active_state = self.state_stack[i]
|
||||||
|
self.active_key = self.key_stack[i]
|
||||||
|
self.stack[i] = nil
|
||||||
|
self.state_stack[i] = nil
|
||||||
|
self.key_stack[i] = nil
|
||||||
|
|
||||||
|
self.i = i - 1
|
||||||
|
end
|
||||||
|
|
||||||
|
function state_ops.push(self)
|
||||||
|
local i = self.i + 1
|
||||||
|
self.i = i
|
||||||
|
|
||||||
|
self.stack[i] = self.active
|
||||||
|
self.state_stack[i] = self.active_state
|
||||||
|
self.key_stack[i] = self.active_key
|
||||||
|
end
|
||||||
|
|
||||||
|
function state_ops.put_object_value(self, trailing)
|
||||||
|
local object_options = self.options.object
|
||||||
|
if trailing and object_options.trailingComma then
|
||||||
|
if not self.active_key then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
assert(self.active_key, "Missing key value")
|
||||||
|
object_options.setObjectKey(self.active, self.active_key, self:grab_value())
|
||||||
|
self.active_key = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
function state_ops.put_array_value(self, trailing)
|
||||||
|
-- Safety check
|
||||||
|
if trailing and not self.previous_set and self.options.array.trailingComma then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
local new_index = self.active_state + 1
|
||||||
|
self.active_state = new_index
|
||||||
|
self.active[new_index] = self:grab_value()
|
||||||
|
end
|
||||||
|
|
||||||
|
function state_ops.put_value(self, trailing)
|
||||||
|
if self.active_state == 'object' then
|
||||||
|
self:put_object_value(trailing)
|
||||||
|
else
|
||||||
|
self:put_array_value(trailing)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function state_ops.new_array(self)
|
||||||
|
local new_array = {}
|
||||||
|
if jsonutil.InitArray then
|
||||||
|
new_array = jsonutil.InitArray(new_array) or new_array
|
||||||
|
end
|
||||||
|
self.active = new_array
|
||||||
|
self.active_state = 0
|
||||||
|
self.active_key = nil
|
||||||
|
self:unset_value()
|
||||||
|
end
|
||||||
|
|
||||||
|
function state_ops.end_array(self)
|
||||||
|
if self.previous_set or self.active_state ~= 0 then
|
||||||
|
-- Not an empty array
|
||||||
|
self:put_value(true)
|
||||||
|
end
|
||||||
|
if self.active_state ~= #self.active then
|
||||||
|
-- Store the length in
|
||||||
|
self.active.n = self.active_state
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function state_ops.new_object(self)
|
||||||
|
local new_object = {}
|
||||||
|
self.active = new_object
|
||||||
|
self.active_state = 'object'
|
||||||
|
self.active_key = nil
|
||||||
|
self:unset_value()
|
||||||
|
end
|
||||||
|
|
||||||
|
function state_ops.end_object(self)
|
||||||
|
if self.previous_set or next(self.active) then
|
||||||
|
-- Not an empty object
|
||||||
|
self:put_value(true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function state_ops.new_call(self, name, func)
|
||||||
|
-- TODO setup properly
|
||||||
|
local new_call = {}
|
||||||
|
new_call.name = name
|
||||||
|
new_call.func = func
|
||||||
|
self.active = new_call
|
||||||
|
self.active_state = 0
|
||||||
|
self.active_key = nil
|
||||||
|
self:unset_value()
|
||||||
|
end
|
||||||
|
|
||||||
|
function state_ops.end_call(self)
|
||||||
|
if self.previous_set or self.active_state ~= 0 then
|
||||||
|
-- Not an empty array
|
||||||
|
self:put_value(true)
|
||||||
|
end
|
||||||
|
if self.active_state ~= #self.active then
|
||||||
|
-- Store the length in
|
||||||
|
self.active.n = self.active_state
|
||||||
|
end
|
||||||
|
local func = self.active.func
|
||||||
|
if func == true then
|
||||||
|
func = jsonutil.buildCall
|
||||||
|
end
|
||||||
|
self.active = func(self.active.name, unpack(self.active, 1, self.active.n or #self.active))
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function state_ops.unset_value(self)
|
||||||
|
self.previous_set = false
|
||||||
|
self.previous = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
function state_ops.grab_value(self)
|
||||||
|
assert(self.previous_set, "Previous value not set")
|
||||||
|
self.previous_set = false
|
||||||
|
return self.previous
|
||||||
|
end
|
||||||
|
|
||||||
|
function state_ops.set_value(self, value)
|
||||||
|
assert(not self.previous_set, "Value set when one already in slot")
|
||||||
|
self.previous_set = true
|
||||||
|
self.previous = value
|
||||||
|
end
|
||||||
|
|
||||||
|
function state_ops.set_key(self)
|
||||||
|
assert(self.active_state == 'object', "Cannot set key on array")
|
||||||
|
local value = self:grab_value()
|
||||||
|
local value_type = type(value)
|
||||||
|
if self.options.object.number then
|
||||||
|
assert(value_type == 'string' or value_type == 'number', "As configured, a key must be a number or string")
|
||||||
|
else
|
||||||
|
assert(value_type == 'string', "As configured, a key must be a string")
|
||||||
|
end
|
||||||
|
self.active_key = value
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local function create(options)
|
||||||
|
local ret = {
|
||||||
|
options = options,
|
||||||
|
stack = {},
|
||||||
|
state_stack = {},
|
||||||
|
key_stack = {},
|
||||||
|
i = 0,
|
||||||
|
active = nil,
|
||||||
|
active_key = nil,
|
||||||
|
previous = nil,
|
||||||
|
active_state = nil
|
||||||
|
|
||||||
|
}
|
||||||
|
return setmetatable(ret, state_mt)
|
||||||
|
end
|
||||||
|
|
||||||
|
local state = {
|
||||||
|
create = create
|
||||||
|
}
|
||||||
|
|
||||||
|
return state
|
133
tools/luajson/json/decode/strings.lua
Normal file
133
tools/luajson/json/decode/strings.lua
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
--[[
|
||||||
|
Licensed according to the included 'LICENSE' document
|
||||||
|
Author: Thomas Harning Jr <harningt@gmail.com>
|
||||||
|
]]
|
||||||
|
local lpeg = require("lpeg")
|
||||||
|
local jsonutil = require("json.util")
|
||||||
|
local util = require("json.decode.util")
|
||||||
|
local merge = jsonutil.merge
|
||||||
|
|
||||||
|
local tonumber = tonumber
|
||||||
|
local string_char = require("string").char
|
||||||
|
local floor = require("math").floor
|
||||||
|
local table_concat = require("table").concat
|
||||||
|
|
||||||
|
local error = error
|
||||||
|
|
||||||
|
local _ENV = nil
|
||||||
|
|
||||||
|
local function get_error(item)
|
||||||
|
local fmt_string = item .. " in string [%q] @ %i:%i"
|
||||||
|
return lpeg.P(function(data, index)
|
||||||
|
local line, line_index, bad_char, last_line = util.get_invalid_character_info(data, index)
|
||||||
|
local err = fmt_string:format(bad_char, line, line_index)
|
||||||
|
error(err)
|
||||||
|
end) * 1
|
||||||
|
end
|
||||||
|
|
||||||
|
local bad_unicode = get_error("Illegal unicode escape")
|
||||||
|
local bad_hex = get_error("Illegal hex escape")
|
||||||
|
local bad_character = get_error("Illegal character")
|
||||||
|
local bad_escape = get_error("Illegal escape")
|
||||||
|
|
||||||
|
local knownReplacements = {
|
||||||
|
["'"] = "'",
|
||||||
|
['"'] = '"',
|
||||||
|
['\\'] = '\\',
|
||||||
|
['/'] = '/',
|
||||||
|
b = '\b',
|
||||||
|
f = '\f',
|
||||||
|
n = '\n',
|
||||||
|
r = '\r',
|
||||||
|
t = '\t',
|
||||||
|
v = '\v',
|
||||||
|
z = '\z'
|
||||||
|
}
|
||||||
|
|
||||||
|
-- according to the table at http://da.wikipedia.org/wiki/UTF-8
|
||||||
|
local function utf8DecodeUnicode(code1, code2)
|
||||||
|
code1, code2 = tonumber(code1, 16), tonumber(code2, 16)
|
||||||
|
if code1 == 0 and code2 < 0x80 then
|
||||||
|
return string_char(code2)
|
||||||
|
end
|
||||||
|
if code1 < 0x08 then
|
||||||
|
return string_char(
|
||||||
|
0xC0 + code1 * 4 + floor(code2 / 64),
|
||||||
|
0x80 + code2 % 64)
|
||||||
|
end
|
||||||
|
return string_char(
|
||||||
|
0xE0 + floor(code1 / 16),
|
||||||
|
0x80 + (code1 % 16) * 4 + floor(code2 / 64),
|
||||||
|
0x80 + code2 % 64)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function decodeX(code)
|
||||||
|
code = tonumber(code, 16)
|
||||||
|
return string_char(code)
|
||||||
|
end
|
||||||
|
|
||||||
|
local doSimpleSub = lpeg.C(lpeg.S("'\"\\/bfnrtvz")) / knownReplacements
|
||||||
|
local doUniSub = lpeg.P('u') * (lpeg.C(util.hexpair) * lpeg.C(util.hexpair) + bad_unicode)
|
||||||
|
local doXSub = lpeg.P('x') * (lpeg.C(util.hexpair) + bad_hex)
|
||||||
|
|
||||||
|
local defaultOptions = {
|
||||||
|
badChars = '',
|
||||||
|
additionalEscapes = false, -- disallow untranslated escapes
|
||||||
|
escapeCheck = #lpeg.S('bfnrtv/\\"xu\'z'), -- no check on valid characters
|
||||||
|
decodeUnicode = utf8DecodeUnicode,
|
||||||
|
strict_quotes = false
|
||||||
|
}
|
||||||
|
|
||||||
|
local modeOptions = {}
|
||||||
|
|
||||||
|
modeOptions.strict = {
|
||||||
|
badChars = '\b\f\n\r\t\v',
|
||||||
|
additionalEscapes = false, -- no additional escapes
|
||||||
|
escapeCheck = #lpeg.S('bfnrtv/\\"u'), --only these chars are allowed to be escaped
|
||||||
|
strict_quotes = true
|
||||||
|
}
|
||||||
|
|
||||||
|
local function mergeOptions(options, mode)
|
||||||
|
jsonutil.doOptionMerge(options, false, 'strings', defaultOptions, mode and modeOptions[mode])
|
||||||
|
end
|
||||||
|
|
||||||
|
local function buildCaptureString(quote, badChars, escapeMatch)
|
||||||
|
local captureChar = (1 - lpeg.S("\\" .. badChars .. quote)) + (lpeg.P("\\") / "" * escapeMatch)
|
||||||
|
-- During error, force end
|
||||||
|
local captureString = captureChar^0 + (-#lpeg.P(quote) * bad_character + -1)
|
||||||
|
return lpeg.P(quote) * lpeg.Cs(captureString) * lpeg.P(quote)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function generateLexer(options)
|
||||||
|
options = options.strings
|
||||||
|
local quotes = { '"' }
|
||||||
|
if not options.strict_quotes then
|
||||||
|
quotes[#quotes + 1] = "'"
|
||||||
|
end
|
||||||
|
local escapeMatch = doSimpleSub
|
||||||
|
escapeMatch = escapeMatch + doXSub / decodeX
|
||||||
|
escapeMatch = escapeMatch + doUniSub / options.decodeUnicode
|
||||||
|
if options.escapeCheck then
|
||||||
|
escapeMatch = options.escapeCheck * escapeMatch + bad_escape
|
||||||
|
end
|
||||||
|
if options.additionalEscapes then
|
||||||
|
escapeMatch = options.additionalEscapes + escapeMatch
|
||||||
|
end
|
||||||
|
local captureString
|
||||||
|
for i = 1, #quotes do
|
||||||
|
local cap = buildCaptureString(quotes[i], options.badChars, escapeMatch)
|
||||||
|
if captureString == nil then
|
||||||
|
captureString = cap
|
||||||
|
else
|
||||||
|
captureString = captureString + cap
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return captureString
|
||||||
|
end
|
||||||
|
|
||||||
|
local strings = {
|
||||||
|
mergeOptions = mergeOptions,
|
||||||
|
generateLexer = generateLexer
|
||||||
|
}
|
||||||
|
|
||||||
|
return strings
|
121
tools/luajson/json/decode/util.lua
Normal file
121
tools/luajson/json/decode/util.lua
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
--[[
|
||||||
|
Licensed according to the included 'LICENSE' document
|
||||||
|
Author: Thomas Harning Jr <harningt@gmail.com>
|
||||||
|
]]
|
||||||
|
local lpeg = require("lpeg")
|
||||||
|
local select = select
|
||||||
|
local pairs, ipairs = pairs, ipairs
|
||||||
|
local tonumber = tonumber
|
||||||
|
local string_char = require("string").char
|
||||||
|
local rawset = rawset
|
||||||
|
local jsonutil = require("json.util")
|
||||||
|
|
||||||
|
local error = error
|
||||||
|
local setmetatable = setmetatable
|
||||||
|
|
||||||
|
local table_concat = require("table").concat
|
||||||
|
|
||||||
|
local merge = require("json.util").merge
|
||||||
|
|
||||||
|
local _ENV = nil
|
||||||
|
|
||||||
|
local function get_invalid_character_info(input, index)
|
||||||
|
local parsed = input:sub(1, index)
|
||||||
|
local bad_character = input:sub(index, index)
|
||||||
|
local _, line_number = parsed:gsub('\n',{})
|
||||||
|
local last_line = parsed:match("\n([^\n]+.)$") or parsed
|
||||||
|
return line_number, #last_line, bad_character, last_line
|
||||||
|
end
|
||||||
|
|
||||||
|
local function build_report(msg)
|
||||||
|
local fmt = msg:gsub("%%", "%%%%") .. " @ character: %i %i:%i [%s] line:\n%s"
|
||||||
|
return lpeg.P(function(data, pos)
|
||||||
|
local line, line_index, bad_char, last_line = get_invalid_character_info(data, pos)
|
||||||
|
local text = fmt:format(pos, line, line_index, bad_char, last_line)
|
||||||
|
error(text)
|
||||||
|
end) * 1
|
||||||
|
end
|
||||||
|
local function unexpected()
|
||||||
|
local msg = "unexpected character"
|
||||||
|
return build_report(msg)
|
||||||
|
end
|
||||||
|
local function denied(item, option)
|
||||||
|
local msg
|
||||||
|
if option then
|
||||||
|
msg = ("'%s' denied by option set '%s'"):format(item, option)
|
||||||
|
else
|
||||||
|
msg = ("'%s' denied"):format(item)
|
||||||
|
end
|
||||||
|
return build_report(msg)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- 09, 0A, 0B, 0C, 0D, 20
|
||||||
|
local ascii_space = lpeg.S("\t\n\v\f\r ")
|
||||||
|
local unicode_space
|
||||||
|
do
|
||||||
|
local chr = string_char
|
||||||
|
local u_space = ascii_space
|
||||||
|
-- \u0085 \u00A0
|
||||||
|
u_space = u_space + lpeg.P(chr(0xC2)) * lpeg.S(chr(0x85) .. chr(0xA0))
|
||||||
|
-- \u1680 \u180E
|
||||||
|
u_space = u_space + lpeg.P(chr(0xE1)) * (lpeg.P(chr(0x9A, 0x80)) + chr(0xA0, 0x8E))
|
||||||
|
-- \u2000 - \u200A, also 200B
|
||||||
|
local spacing_end = ""
|
||||||
|
for i = 0x80,0x8b do
|
||||||
|
spacing_end = spacing_end .. chr(i)
|
||||||
|
end
|
||||||
|
-- \u2028 \u2029 \u202F
|
||||||
|
spacing_end = spacing_end .. chr(0xA8) .. chr(0xA9) .. chr(0xAF)
|
||||||
|
u_space = u_space + lpeg.P(chr(0xE2, 0x80)) * lpeg.S(spacing_end)
|
||||||
|
-- \u205F
|
||||||
|
u_space = u_space + lpeg.P(chr(0xE2, 0x81, 0x9F))
|
||||||
|
-- \u3000
|
||||||
|
u_space = u_space + lpeg.P(chr(0xE3, 0x80, 0x80))
|
||||||
|
-- BOM \uFEFF
|
||||||
|
u_space = u_space + lpeg.P(chr(0xEF, 0xBB, 0xBF))
|
||||||
|
unicode_space = u_space
|
||||||
|
end
|
||||||
|
|
||||||
|
local identifier = lpeg.R("AZ","az","__") * lpeg.R("AZ","az", "__", "09") ^0
|
||||||
|
|
||||||
|
local hex = lpeg.R("09","AF","af")
|
||||||
|
local hexpair = hex * hex
|
||||||
|
|
||||||
|
local comments = {
|
||||||
|
cpp = lpeg.P("//") * (1 - lpeg.P("\n"))^0 * lpeg.P("\n"),
|
||||||
|
c = lpeg.P("/*") * (1 - lpeg.P("*/"))^0 * lpeg.P("*/")
|
||||||
|
}
|
||||||
|
|
||||||
|
local comment = comments.cpp + comments.c
|
||||||
|
|
||||||
|
local ascii_ignored = (ascii_space + comment)^0
|
||||||
|
|
||||||
|
local unicode_ignored = (unicode_space + comment)^0
|
||||||
|
|
||||||
|
-- Parse the lpeg version skipping patch-values
|
||||||
|
-- LPEG <= 0.7 have no version value... so 0.7 is value
|
||||||
|
local DecimalLpegVersion = lpeg.version and tonumber(lpeg.version():match("^(%d+%.%d+)")) or 0.7
|
||||||
|
|
||||||
|
local function setObjectKeyForceNumber(t, key, value)
|
||||||
|
key = tonumber(key) or key
|
||||||
|
return rawset(t, key, value)
|
||||||
|
end
|
||||||
|
|
||||||
|
local util = {
|
||||||
|
unexpected = unexpected,
|
||||||
|
denied = denied,
|
||||||
|
ascii_space = ascii_space,
|
||||||
|
unicode_space = unicode_space,
|
||||||
|
identifier = identifier,
|
||||||
|
hex = hex,
|
||||||
|
hexpair = hexpair,
|
||||||
|
comments = comments,
|
||||||
|
comment = comment,
|
||||||
|
ascii_ignored = ascii_ignored,
|
||||||
|
unicode_ignored = unicode_ignored,
|
||||||
|
DecimalLpegVersion = DecimalLpegVersion,
|
||||||
|
get_invalid_character_info = get_invalid_character_info,
|
||||||
|
setObjectKeyForceNumber = setObjectKeyForceNumber
|
||||||
|
}
|
||||||
|
|
||||||
|
return util
|
161
tools/luajson/json/encode.lua
Normal file
161
tools/luajson/json/encode.lua
Normal file
@ -0,0 +1,161 @@
|
|||||||
|
--[[
|
||||||
|
Licensed according to the included 'LICENSE' document
|
||||||
|
Author: Thomas Harning Jr <harningt@gmail.com>
|
||||||
|
]]
|
||||||
|
local type = type
|
||||||
|
local assert, error = assert, error
|
||||||
|
local getmetatable, setmetatable = getmetatable, setmetatable
|
||||||
|
|
||||||
|
local ipairs, pairs = ipairs, pairs
|
||||||
|
local require = require
|
||||||
|
|
||||||
|
local output = require("json.encode.output")
|
||||||
|
|
||||||
|
local util = require("json.util")
|
||||||
|
local util_merge, isCall = util.merge, util.isCall
|
||||||
|
|
||||||
|
local _ENV = nil
|
||||||
|
|
||||||
|
--[[
|
||||||
|
List of encoding modules to load.
|
||||||
|
Loaded in sequence such that earlier encoders get priority when
|
||||||
|
duplicate type-handlers exist.
|
||||||
|
]]
|
||||||
|
local modulesToLoad = {
|
||||||
|
"strings",
|
||||||
|
"number",
|
||||||
|
"calls",
|
||||||
|
"others",
|
||||||
|
"array",
|
||||||
|
"object"
|
||||||
|
}
|
||||||
|
-- Modules that have been loaded
|
||||||
|
local loadedModules = {}
|
||||||
|
|
||||||
|
local json_encode = {}
|
||||||
|
|
||||||
|
-- Configuration bases for client apps
|
||||||
|
local modes_defined = { "default", "strict" }
|
||||||
|
|
||||||
|
json_encode.default = {}
|
||||||
|
json_encode.strict = {
|
||||||
|
initialObject = true -- Require an object at the root
|
||||||
|
}
|
||||||
|
|
||||||
|
-- For each module, load it and its defaults
|
||||||
|
for _,name in ipairs(modulesToLoad) do
|
||||||
|
local mod = require("json.encode." .. name)
|
||||||
|
if mod.mergeOptions then
|
||||||
|
for _, mode in pairs(modes_defined) do
|
||||||
|
mod.mergeOptions(json_encode[mode], mode)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
loadedModules[name] = mod
|
||||||
|
end
|
||||||
|
|
||||||
|
-- NOTE: Nested not found, so assume unsupported until use case arises
|
||||||
|
local function flattenOutput(out, value)
|
||||||
|
assert(type(value) ~= 'table')
|
||||||
|
out = out or {}
|
||||||
|
out[#out + 1] = value
|
||||||
|
return out
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Prepares the encoding map from the already provided modules and new config
|
||||||
|
local function prepareEncodeMap(options)
|
||||||
|
local map = {}
|
||||||
|
for _, name in ipairs(modulesToLoad) do
|
||||||
|
local encodermap = loadedModules[name].getEncoder(options[name])
|
||||||
|
for valueType, encoderSet in pairs(encodermap) do
|
||||||
|
map[valueType] = flattenOutput(map[valueType], encoderSet)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return map
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[
|
||||||
|
Encode a value with a given encoding map and state
|
||||||
|
]]
|
||||||
|
local function encodeWithMap(value, map, state, isObjectKey)
|
||||||
|
local t = type(value)
|
||||||
|
local encoderList = assert(map[t], "Failed to encode value, unhandled type: " .. t)
|
||||||
|
for _, encoder in ipairs(encoderList) do
|
||||||
|
local ret = encoder(value, state, isObjectKey)
|
||||||
|
if false ~= ret then
|
||||||
|
return ret
|
||||||
|
end
|
||||||
|
end
|
||||||
|
error("Failed to encode value, encoders for " .. t .. " deny encoding")
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local function getBaseEncoder(options)
|
||||||
|
local encoderMap = prepareEncodeMap(options)
|
||||||
|
if options.preProcess then
|
||||||
|
local preProcess = options.preProcess
|
||||||
|
return function(value, state, isObjectKey)
|
||||||
|
local ret = preProcess(value, isObjectKey or false)
|
||||||
|
if nil ~= ret then
|
||||||
|
value = ret
|
||||||
|
end
|
||||||
|
return encodeWithMap(value, encoderMap, state)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return function(value, state, isObjectKey)
|
||||||
|
return encodeWithMap(value, encoderMap, state)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
--[[
|
||||||
|
Retreive an initial encoder instance based on provided options
|
||||||
|
the initial encoder is responsible for initializing state
|
||||||
|
State has at least these values configured: encode, check_unique, already_encoded
|
||||||
|
]]
|
||||||
|
function json_encode.getEncoder(options)
|
||||||
|
options = options and util_merge({}, json_encode.default, options) or json_encode.default
|
||||||
|
local encode = getBaseEncoder(options)
|
||||||
|
|
||||||
|
local function initialEncode(value)
|
||||||
|
if options.initialObject then
|
||||||
|
local errorMessage = "Invalid arguments: expects a JSON Object or Array at the root"
|
||||||
|
assert(type(value) == 'table' and not isCall(value, options), errorMessage)
|
||||||
|
end
|
||||||
|
|
||||||
|
local alreadyEncoded = {}
|
||||||
|
local function check_unique(value)
|
||||||
|
assert(not alreadyEncoded[value], "Recursive encoding of value")
|
||||||
|
alreadyEncoded[value] = true
|
||||||
|
end
|
||||||
|
|
||||||
|
local outputEncoder = options.output and options.output() or output.getDefault()
|
||||||
|
local state = {
|
||||||
|
encode = encode,
|
||||||
|
check_unique = check_unique,
|
||||||
|
already_encoded = alreadyEncoded, -- To unmark encoding when moving up stack
|
||||||
|
outputEncoder = outputEncoder
|
||||||
|
}
|
||||||
|
local ret = encode(value, state)
|
||||||
|
if nil ~= ret then
|
||||||
|
return outputEncoder.simple and outputEncoder.simple(ret) or ret
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return initialEncode
|
||||||
|
end
|
||||||
|
|
||||||
|
-- CONSTRUCT STATE WITH FOLLOWING (at least)
|
||||||
|
--[[
|
||||||
|
encoder
|
||||||
|
check_unique -- used by inner encoders to make sure value is unique
|
||||||
|
already_encoded -- used to unmark a value as unique
|
||||||
|
]]
|
||||||
|
function json_encode.encode(data, options)
|
||||||
|
return json_encode.getEncoder(options)(data)
|
||||||
|
end
|
||||||
|
|
||||||
|
local mt = {}
|
||||||
|
mt.__call = function(self, ...)
|
||||||
|
return json_encode.encode(...)
|
||||||
|
end
|
||||||
|
|
||||||
|
setmetatable(json_encode, mt)
|
||||||
|
|
||||||
|
return json_encode
|
110
tools/luajson/json/encode/array.lua
Normal file
110
tools/luajson/json/encode/array.lua
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
--[[
|
||||||
|
Licensed according to the included 'LICENSE' document
|
||||||
|
Author: Thomas Harning Jr <harningt@gmail.com>
|
||||||
|
]]
|
||||||
|
local jsonutil = require("json.util")
|
||||||
|
|
||||||
|
local type = type
|
||||||
|
local pairs = pairs
|
||||||
|
local assert = assert
|
||||||
|
|
||||||
|
local table = require("table")
|
||||||
|
local math = require("math")
|
||||||
|
local table_concat = table.concat
|
||||||
|
local math_floor, math_modf = math.floor, math.modf
|
||||||
|
|
||||||
|
local jsonutil = require("json.util")
|
||||||
|
local util_IsArray = jsonutil.IsArray
|
||||||
|
|
||||||
|
local _ENV = nil
|
||||||
|
|
||||||
|
local defaultOptions = {
|
||||||
|
isArray = util_IsArray
|
||||||
|
}
|
||||||
|
|
||||||
|
local modeOptions = {}
|
||||||
|
|
||||||
|
local function mergeOptions(options, mode)
|
||||||
|
jsonutil.doOptionMerge(options, false, 'array', defaultOptions, mode and modeOptions[mode])
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[
|
||||||
|
Utility function to determine whether a table is an array or not.
|
||||||
|
Criteria for it being an array:
|
||||||
|
* ExternalIsArray returns true (or false directly reports not-array)
|
||||||
|
* If the table has an 'n' value that is an integer >= 1 then it
|
||||||
|
is an array... may result in false positives (should check some values
|
||||||
|
before it)
|
||||||
|
* It is a contiguous list of values with zero string-based keys
|
||||||
|
]]
|
||||||
|
local function isArray(val, options)
|
||||||
|
local externalIsArray = options and options.isArray
|
||||||
|
|
||||||
|
if externalIsArray then
|
||||||
|
local ret = externalIsArray(val)
|
||||||
|
if ret == true or ret == false then
|
||||||
|
return ret
|
||||||
|
end
|
||||||
|
end
|
||||||
|
-- Use the 'n' element if it's a number
|
||||||
|
if type(val.n) == 'number' and math_floor(val.n) == val.n and val.n >= 1 then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
local len = #val
|
||||||
|
for k,v in pairs(val) do
|
||||||
|
if type(k) ~= 'number' then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
local _, decim = math_modf(k)
|
||||||
|
if not (decim == 0 and 1<=k) then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
if k > len then -- Use Lua's length as absolute determiner
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[
|
||||||
|
Cleanup function to unmark a value as in the encoding process and return
|
||||||
|
trailing results
|
||||||
|
]]
|
||||||
|
local function unmarkAfterEncode(tab, state, ...)
|
||||||
|
state.already_encoded[tab] = nil
|
||||||
|
return ...
|
||||||
|
end
|
||||||
|
local function getEncoder(options)
|
||||||
|
options = options and jsonutil.merge({}, defaultOptions, options) or defaultOptions
|
||||||
|
local function encodeArray(tab, state)
|
||||||
|
if not isArray(tab, options) then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
-- Make sure this value hasn't been encoded yet
|
||||||
|
state.check_unique(tab)
|
||||||
|
local encode = state.encode
|
||||||
|
local compositeEncoder = state.outputEncoder.composite
|
||||||
|
local valueEncoder = [[
|
||||||
|
for i = 1, (composite.n or #composite) do
|
||||||
|
local val = composite[i]
|
||||||
|
PUTINNER(i ~= 1)
|
||||||
|
val = encode(val, state)
|
||||||
|
val = val or ''
|
||||||
|
if val then
|
||||||
|
PUTVALUE(val)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
]]
|
||||||
|
return unmarkAfterEncode(tab, state, compositeEncoder(valueEncoder, '[', ']', ',', tab, encode, state))
|
||||||
|
end
|
||||||
|
return { table = encodeArray }
|
||||||
|
end
|
||||||
|
|
||||||
|
local array = {
|
||||||
|
mergeOptions = mergeOptions,
|
||||||
|
isArray = isArray,
|
||||||
|
getEncoder = getEncoder
|
||||||
|
}
|
||||||
|
|
||||||
|
return array
|
68
tools/luajson/json/encode/calls.lua
Normal file
68
tools/luajson/json/encode/calls.lua
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
--[[
|
||||||
|
Licensed according to the included 'LICENSE' document
|
||||||
|
Author: Thomas Harning Jr <harningt@gmail.com>
|
||||||
|
]]
|
||||||
|
local table = require("table")
|
||||||
|
local table_concat = table.concat
|
||||||
|
|
||||||
|
local select = select
|
||||||
|
local getmetatable, setmetatable = getmetatable, setmetatable
|
||||||
|
local assert = assert
|
||||||
|
|
||||||
|
local jsonutil = require("json.util")
|
||||||
|
|
||||||
|
local isCall, decodeCall = jsonutil.isCall, jsonutil.decodeCall
|
||||||
|
|
||||||
|
local _ENV = nil
|
||||||
|
|
||||||
|
local defaultOptions = {
|
||||||
|
}
|
||||||
|
|
||||||
|
-- No real default-option handling needed...
|
||||||
|
local modeOptions = {}
|
||||||
|
|
||||||
|
local function mergeOptions(options, mode)
|
||||||
|
jsonutil.doOptionMerge(options, false, 'calls', defaultOptions, mode and modeOptions[mode])
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--[[
|
||||||
|
Encodes 'value' as a function call
|
||||||
|
Must have parameters in the 'callData' field of the metatable
|
||||||
|
name == name of the function call
|
||||||
|
parameters == array of parameters to encode
|
||||||
|
]]
|
||||||
|
local function getEncoder(options)
|
||||||
|
options = options and jsonutil.merge({}, defaultOptions, options) or defaultOptions
|
||||||
|
local function encodeCall(value, state)
|
||||||
|
if not isCall(value) then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
local encode = state.encode
|
||||||
|
local name, params = decodeCall(value)
|
||||||
|
local compositeEncoder = state.outputEncoder.composite
|
||||||
|
local valueEncoder = [[
|
||||||
|
for i = 1, (composite.n or #composite) do
|
||||||
|
local val = composite[i]
|
||||||
|
PUTINNER(i ~= 1)
|
||||||
|
val = encode(val, state)
|
||||||
|
val = val or ''
|
||||||
|
if val then
|
||||||
|
PUTVALUE(val)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
]]
|
||||||
|
return compositeEncoder(valueEncoder, name .. '(', ')', ',', params, encode, state)
|
||||||
|
end
|
||||||
|
return {
|
||||||
|
table = encodeCall,
|
||||||
|
['function'] = encodeCall
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
local calls = {
|
||||||
|
mergeOptions = mergeOptions,
|
||||||
|
getEncoder = getEncoder
|
||||||
|
}
|
||||||
|
|
||||||
|
return calls
|
58
tools/luajson/json/encode/number.lua
Normal file
58
tools/luajson/json/encode/number.lua
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
--[[
|
||||||
|
Licensed according to the included 'LICENSE' document
|
||||||
|
Author: Thomas Harning Jr <harningt@gmail.com>
|
||||||
|
]]
|
||||||
|
local tostring = tostring
|
||||||
|
local assert = assert
|
||||||
|
local jsonutil = require("json.util")
|
||||||
|
local huge = require("math").huge
|
||||||
|
|
||||||
|
local _ENV = nil
|
||||||
|
|
||||||
|
local defaultOptions = {
|
||||||
|
nan = true,
|
||||||
|
inf = true
|
||||||
|
}
|
||||||
|
|
||||||
|
local modeOptions = {}
|
||||||
|
modeOptions.strict = {
|
||||||
|
nan = false,
|
||||||
|
inf = false
|
||||||
|
}
|
||||||
|
|
||||||
|
local function mergeOptions(options, mode)
|
||||||
|
jsonutil.doOptionMerge(options, false, 'number', defaultOptions, mode and modeOptions[mode])
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local function encodeNumber(number, options)
|
||||||
|
if number ~= number then
|
||||||
|
assert(options.nan, "Invalid number: NaN not enabled")
|
||||||
|
return "NaN"
|
||||||
|
end
|
||||||
|
if number == huge then
|
||||||
|
assert(options.inf, "Invalid number: Infinity not enabled")
|
||||||
|
return "Infinity"
|
||||||
|
end
|
||||||
|
if number == -huge then
|
||||||
|
assert(options.inf, "Invalid number: Infinity not enabled")
|
||||||
|
return "-Infinity"
|
||||||
|
end
|
||||||
|
return tostring(number)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function getEncoder(options)
|
||||||
|
options = options and jsonutil.merge({}, defaultOptions, options) or defaultOptions
|
||||||
|
return {
|
||||||
|
number = function(number, state)
|
||||||
|
return encodeNumber(number, options)
|
||||||
|
end
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
local number = {
|
||||||
|
mergeOptions = mergeOptions,
|
||||||
|
getEncoder = getEncoder
|
||||||
|
}
|
||||||
|
|
||||||
|
return number
|
77
tools/luajson/json/encode/object.lua
Normal file
77
tools/luajson/json/encode/object.lua
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
--[[
|
||||||
|
Licensed according to the included 'LICENSE' document
|
||||||
|
Author: Thomas Harning Jr <harningt@gmail.com>
|
||||||
|
]]
|
||||||
|
local pairs = pairs
|
||||||
|
local assert = assert
|
||||||
|
|
||||||
|
local type = type
|
||||||
|
local tostring = tostring
|
||||||
|
|
||||||
|
local table_concat = require("table").concat
|
||||||
|
local jsonutil = require("json.util")
|
||||||
|
|
||||||
|
local _ENV = nil
|
||||||
|
|
||||||
|
local defaultOptions = {
|
||||||
|
}
|
||||||
|
|
||||||
|
local modeOptions = {}
|
||||||
|
|
||||||
|
local function mergeOptions(options, mode)
|
||||||
|
jsonutil.doOptionMerge(options, false, 'object', defaultOptions, mode and modeOptions[mode])
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[
|
||||||
|
Cleanup function to unmark a value as in the encoding process and return
|
||||||
|
trailing results
|
||||||
|
]]
|
||||||
|
local function unmarkAfterEncode(tab, state, ...)
|
||||||
|
state.already_encoded[tab] = nil
|
||||||
|
return ...
|
||||||
|
end
|
||||||
|
--[[
|
||||||
|
Encode a table as a JSON Object ( keys = strings, values = anything else )
|
||||||
|
]]
|
||||||
|
local function encodeTable(tab, options, state)
|
||||||
|
-- Make sure this value hasn't been encoded yet
|
||||||
|
state.check_unique(tab)
|
||||||
|
local encode = state.encode
|
||||||
|
local compositeEncoder = state.outputEncoder.composite
|
||||||
|
local valueEncoder = [[
|
||||||
|
local first = true
|
||||||
|
for k, v in pairs(composite) do
|
||||||
|
local ti = type(k)
|
||||||
|
assert(ti == 'string' or ti == 'number' or ti == 'boolean', "Invalid object index type: " .. ti)
|
||||||
|
local name = encode(tostring(k), state, true)
|
||||||
|
if first then
|
||||||
|
first = false
|
||||||
|
else
|
||||||
|
name = ',' .. name
|
||||||
|
end
|
||||||
|
PUTVALUE(name .. ':')
|
||||||
|
local val = encode(v, state)
|
||||||
|
val = val or ''
|
||||||
|
if val then
|
||||||
|
PUTVALUE(val)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
]]
|
||||||
|
return unmarkAfterEncode(tab, state, compositeEncoder(valueEncoder, '{', '}', nil, tab, encode, state))
|
||||||
|
end
|
||||||
|
|
||||||
|
local function getEncoder(options)
|
||||||
|
options = options and jsonutil.merge({}, defaultOptions, options) or defaultOptions
|
||||||
|
return {
|
||||||
|
table = function(tab, state)
|
||||||
|
return encodeTable(tab, options, state)
|
||||||
|
end
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
local object = {
|
||||||
|
mergeOptions = mergeOptions,
|
||||||
|
getEncoder = getEncoder
|
||||||
|
}
|
||||||
|
|
||||||
|
return object
|
66
tools/luajson/json/encode/others.lua
Normal file
66
tools/luajson/json/encode/others.lua
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
--[[
|
||||||
|
Licensed according to the included 'LICENSE' document
|
||||||
|
Author: Thomas Harning Jr <harningt@gmail.com>
|
||||||
|
]]
|
||||||
|
local tostring = tostring
|
||||||
|
|
||||||
|
local assert = assert
|
||||||
|
local jsonutil = require("json.util")
|
||||||
|
local type = type
|
||||||
|
|
||||||
|
local _ENV = nil
|
||||||
|
|
||||||
|
-- Shortcut that works
|
||||||
|
local encodeBoolean = tostring
|
||||||
|
|
||||||
|
local defaultOptions = {
|
||||||
|
allowUndefined = true,
|
||||||
|
null = jsonutil.null,
|
||||||
|
undefined = jsonutil.undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
local modeOptions = {}
|
||||||
|
|
||||||
|
modeOptions.strict = {
|
||||||
|
allowUndefined = false
|
||||||
|
}
|
||||||
|
|
||||||
|
local function mergeOptions(options, mode)
|
||||||
|
jsonutil.doOptionMerge(options, false, 'others', defaultOptions, mode and modeOptions[mode])
|
||||||
|
end
|
||||||
|
local function getEncoder(options)
|
||||||
|
options = options and jsonutil.merge({}, defaultOptions, options) or defaultOptions
|
||||||
|
local function encodeOthers(value, state)
|
||||||
|
if value == options.null then
|
||||||
|
return 'null'
|
||||||
|
elseif value == options.undefined then
|
||||||
|
assert(options.allowUndefined, "Invalid value: Unsupported 'Undefined' parameter")
|
||||||
|
return 'undefined'
|
||||||
|
else
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
local function encodeBoolean(value, state)
|
||||||
|
return value and 'true' or 'false'
|
||||||
|
end
|
||||||
|
local nullType = type(options.null)
|
||||||
|
local undefinedType = options.undefined and type(options.undefined)
|
||||||
|
-- Make sure that all of the types handled here are handled
|
||||||
|
local ret = {
|
||||||
|
boolean = encodeBoolean,
|
||||||
|
['nil'] = function() return 'null' end,
|
||||||
|
[nullType] = encodeOthers
|
||||||
|
}
|
||||||
|
if undefinedType then
|
||||||
|
ret[undefinedType] = encodeOthers
|
||||||
|
end
|
||||||
|
return ret
|
||||||
|
end
|
||||||
|
|
||||||
|
local others = {
|
||||||
|
encodeBoolean = encodeBoolean,
|
||||||
|
mergeOptions = mergeOptions,
|
||||||
|
getEncoder = getEncoder
|
||||||
|
}
|
||||||
|
|
||||||
|
return others
|
91
tools/luajson/json/encode/output.lua
Normal file
91
tools/luajson/json/encode/output.lua
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
--[[
|
||||||
|
Licensed according to the included 'LICENSE' document
|
||||||
|
Author: Thomas Harning Jr <harningt@gmail.com>
|
||||||
|
]]
|
||||||
|
local type = type
|
||||||
|
local assert, error = assert, error
|
||||||
|
local table_concat = require("table").concat
|
||||||
|
local loadstring = loadstring or load
|
||||||
|
|
||||||
|
local io = require("io")
|
||||||
|
|
||||||
|
local setmetatable = setmetatable
|
||||||
|
|
||||||
|
local output_utility = require("json.encode.output_utility")
|
||||||
|
|
||||||
|
local _ENV = nil
|
||||||
|
|
||||||
|
local tableCompositeCache = setmetatable({}, {__mode = 'v'})
|
||||||
|
|
||||||
|
local TABLE_VALUE_WRITER = [[
|
||||||
|
ret[#ret + 1] = %VALUE%
|
||||||
|
]]
|
||||||
|
|
||||||
|
local TABLE_INNER_WRITER = ""
|
||||||
|
|
||||||
|
--[[
|
||||||
|
nextValues can output a max of two values to throw into the data stream
|
||||||
|
expected to be called until nil is first return value
|
||||||
|
value separator should either be attached to v1 or in innerValue
|
||||||
|
]]
|
||||||
|
local function defaultTableCompositeWriter(nextValues, beginValue, closeValue, innerValue, composite, encode, state)
|
||||||
|
if type(nextValues) == 'string' then
|
||||||
|
local fun = output_utility.prepareEncoder(defaultTableCompositeWriter, nextValues, innerValue, TABLE_VALUE_WRITER, TABLE_INNER_WRITER)
|
||||||
|
local ret = {}
|
||||||
|
fun(composite, ret, encode, state)
|
||||||
|
return beginValue .. table_concat(ret, innerValue) .. closeValue
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- no 'simple' as default action is just to return the value
|
||||||
|
local function getDefault()
|
||||||
|
return { composite = defaultTableCompositeWriter }
|
||||||
|
end
|
||||||
|
|
||||||
|
-- BEGIN IO-WRITER OUTPUT
|
||||||
|
local IO_INNER_WRITER = [[
|
||||||
|
if %WRITE_INNER% then
|
||||||
|
state.__outputFile:write(%INNER_VALUE%)
|
||||||
|
end
|
||||||
|
]]
|
||||||
|
local IO_VALUE_WRITER = [[
|
||||||
|
state.__outputFile:write(%VALUE%)
|
||||||
|
]]
|
||||||
|
|
||||||
|
local function buildIoWriter(output)
|
||||||
|
if not output then -- Default to stdout
|
||||||
|
output = io.output()
|
||||||
|
end
|
||||||
|
local function ioWriter(nextValues, beginValue, closeValue, innerValue, composite, encode, state)
|
||||||
|
-- HOOK OUTPUT STATE
|
||||||
|
state.__outputFile = output
|
||||||
|
if type(nextValues) == 'string' then
|
||||||
|
local fun = output_utility.prepareEncoder(ioWriter, nextValues, innerValue, IO_VALUE_WRITER, IO_INNER_WRITER)
|
||||||
|
local ret = {}
|
||||||
|
output:write(beginValue)
|
||||||
|
fun(composite, ret, encode, state)
|
||||||
|
output:write(closeValue)
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function ioSimpleWriter(encoded)
|
||||||
|
if encoded then
|
||||||
|
output:write(encoded)
|
||||||
|
end
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
return { composite = ioWriter, simple = ioSimpleWriter }
|
||||||
|
end
|
||||||
|
local function getIoWriter(output)
|
||||||
|
return function()
|
||||||
|
return buildIoWriter(output)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local output = {
|
||||||
|
getDefault = getDefault,
|
||||||
|
getIoWriter = getIoWriter
|
||||||
|
}
|
||||||
|
|
||||||
|
return output
|
54
tools/luajson/json/encode/output_utility.lua
Normal file
54
tools/luajson/json/encode/output_utility.lua
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
--[[
|
||||||
|
Licensed according to the included 'LICENSE' document
|
||||||
|
Author: Thomas Harning Jr <harningt@gmail.com>
|
||||||
|
]]
|
||||||
|
local setmetatable = setmetatable
|
||||||
|
local assert, loadstring = assert, loadstring or load
|
||||||
|
|
||||||
|
local _ENV = nil
|
||||||
|
|
||||||
|
-- Key == weak, if main key goes away, then cache cleared
|
||||||
|
local outputCache = setmetatable({}, {__mode = 'k'})
|
||||||
|
-- TODO: inner tables weak?
|
||||||
|
|
||||||
|
local function buildFunction(nextValues, innerValue, valueWriter, innerWriter)
|
||||||
|
local putInner = ""
|
||||||
|
if innerValue and innerWriter then
|
||||||
|
-- Prepare the lua-string representation of the separator to put in between values
|
||||||
|
local formattedInnerValue = ("%q"):format(innerValue)
|
||||||
|
-- Fill in the condition %WRITE_INNER% and the %INNER_VALUE% to actually write
|
||||||
|
putInner = innerWriter:gsub("%%WRITE_INNER%%", "%%1"):gsub("%%INNER_VALUE%%", formattedInnerValue)
|
||||||
|
end
|
||||||
|
-- Template-in the value writer (if present) and its conditional argument
|
||||||
|
local functionCode = nextValues:gsub("PUTINNER(%b())", putInner)
|
||||||
|
-- %VALUE% is to be filled in by the value-to-write
|
||||||
|
valueWriter = valueWriter:gsub("%%VALUE%%", "%%1")
|
||||||
|
-- Template-in the value writer with its argument
|
||||||
|
functionCode = functionCode:gsub("PUTVALUE(%b())", valueWriter)
|
||||||
|
functionCode = [[
|
||||||
|
return function(composite, ret, encode, state)
|
||||||
|
]] .. functionCode .. [[
|
||||||
|
end
|
||||||
|
]]
|
||||||
|
return assert(loadstring(functionCode))()
|
||||||
|
end
|
||||||
|
|
||||||
|
local function prepareEncoder(cacheKey, nextValues, innerValue, valueWriter, innerWriter)
|
||||||
|
local cache = outputCache[cacheKey]
|
||||||
|
if not cache then
|
||||||
|
cache = {}
|
||||||
|
outputCache[cacheKey] = cache
|
||||||
|
end
|
||||||
|
local fun = cache[nextValues]
|
||||||
|
if not fun then
|
||||||
|
fun = buildFunction(nextValues, innerValue, valueWriter, innerWriter)
|
||||||
|
cache[nextValues] = fun
|
||||||
|
end
|
||||||
|
return fun
|
||||||
|
end
|
||||||
|
|
||||||
|
local output_utility = {
|
||||||
|
prepareEncoder = prepareEncoder
|
||||||
|
}
|
||||||
|
|
||||||
|
return output_utility
|
88
tools/luajson/json/encode/strings.lua
Normal file
88
tools/luajson/json/encode/strings.lua
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
--[[
|
||||||
|
Licensed according to the included 'LICENSE' document
|
||||||
|
Author: Thomas Harning Jr <harningt@gmail.com>
|
||||||
|
]]
|
||||||
|
local string_char = require("string").char
|
||||||
|
local pairs = pairs
|
||||||
|
|
||||||
|
local jsonutil = require("json.util")
|
||||||
|
local util_merge = jsonutil.merge
|
||||||
|
|
||||||
|
local _ENV = nil
|
||||||
|
|
||||||
|
local normalEncodingMap = {
|
||||||
|
['"'] = '\\"',
|
||||||
|
['\\'] = '\\\\',
|
||||||
|
['/'] = '\\/',
|
||||||
|
['\b'] = '\\b',
|
||||||
|
['\f'] = '\\f',
|
||||||
|
['\n'] = '\\n',
|
||||||
|
['\r'] = '\\r',
|
||||||
|
['\t'] = '\\t',
|
||||||
|
['\v'] = '\\v' -- not in official spec, on report, removing
|
||||||
|
}
|
||||||
|
|
||||||
|
local xEncodingMap = {}
|
||||||
|
for char, encoded in pairs(normalEncodingMap) do
|
||||||
|
xEncodingMap[char] = encoded
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Pre-encode the control characters to speed up encoding...
|
||||||
|
-- NOTE: UTF-8 may not work out right w/ JavaScript
|
||||||
|
-- JavaScript uses 2 bytes after a \u... yet UTF-8 is a
|
||||||
|
-- byte-stream encoding, not pairs of bytes (it does encode
|
||||||
|
-- some letters > 1 byte, but base case is 1)
|
||||||
|
for i = 0, 255 do
|
||||||
|
local c = string_char(i)
|
||||||
|
if c:match('[%z\1-\031\128-\255]') and not normalEncodingMap[c] then
|
||||||
|
-- WARN: UTF8 specializes values >= 0x80 as parts of sequences...
|
||||||
|
-- without \x encoding, do not allow encoding > 7F
|
||||||
|
normalEncodingMap[c] = ('\\u%.4X'):format(i)
|
||||||
|
xEncodingMap[c] = ('\\x%.2X'):format(i)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local defaultOptions = {
|
||||||
|
xEncode = false, -- Encode single-bytes as \xXX
|
||||||
|
processor = nil, -- Simple processor for the string prior to quoting
|
||||||
|
-- / is not required to be quoted but it helps with certain decoding
|
||||||
|
-- Required encoded characters, " \, and 00-1F (0 - 31)
|
||||||
|
encodeSet = '\\"/%z\1-\031',
|
||||||
|
encodeSetAppend = nil -- Chars to append to the default set
|
||||||
|
}
|
||||||
|
|
||||||
|
local modeOptions = {}
|
||||||
|
|
||||||
|
local function mergeOptions(options, mode)
|
||||||
|
jsonutil.doOptionMerge(options, false, 'strings', defaultOptions, mode and modeOptions[mode])
|
||||||
|
end
|
||||||
|
|
||||||
|
local function getEncoder(options)
|
||||||
|
options = options and util_merge({}, defaultOptions, options) or defaultOptions
|
||||||
|
local encodeSet = options.encodeSet
|
||||||
|
if options.encodeSetAppend then
|
||||||
|
encodeSet = encodeSet .. options.encodeSetAppend
|
||||||
|
end
|
||||||
|
local encodingMap = options.xEncode and xEncodingMap or normalEncodingMap
|
||||||
|
local encodeString
|
||||||
|
if options.processor then
|
||||||
|
local processor = options.processor
|
||||||
|
encodeString = function(s, state)
|
||||||
|
return '"' .. processor(s:gsub('[' .. encodeSet .. ']', encodingMap)) .. '"'
|
||||||
|
end
|
||||||
|
else
|
||||||
|
encodeString = function(s, state)
|
||||||
|
return '"' .. s:gsub('[' .. encodeSet .. ']', encodingMap) .. '"'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return {
|
||||||
|
string = encodeString
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
local strings = {
|
||||||
|
mergeOptions = mergeOptions,
|
||||||
|
getEncoder = getEncoder
|
||||||
|
}
|
||||||
|
|
||||||
|
return strings
|
152
tools/luajson/json/util.lua
Normal file
152
tools/luajson/json/util.lua
Normal file
@ -0,0 +1,152 @@
|
|||||||
|
--[[
|
||||||
|
Licensed according to the included 'LICENSE' document
|
||||||
|
Author: Thomas Harning Jr <harningt@gmail.com>
|
||||||
|
]]
|
||||||
|
local type = type
|
||||||
|
local print = print
|
||||||
|
local tostring = tostring
|
||||||
|
local pairs = pairs
|
||||||
|
local getmetatable, setmetatable = getmetatable, setmetatable
|
||||||
|
local select = select
|
||||||
|
|
||||||
|
local _ENV = nil
|
||||||
|
|
||||||
|
local function foreach(tab, func)
|
||||||
|
for k, v in pairs(tab) do
|
||||||
|
func(k,v)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
local function printValue(tab, name)
|
||||||
|
local parsed = {}
|
||||||
|
local function doPrint(key, value, space)
|
||||||
|
space = space or ''
|
||||||
|
if type(value) == 'table' then
|
||||||
|
if parsed[value] then
|
||||||
|
print(space .. key .. '= <' .. parsed[value] .. '>')
|
||||||
|
else
|
||||||
|
parsed[value] = key
|
||||||
|
print(space .. key .. '= {')
|
||||||
|
space = space .. ' '
|
||||||
|
foreach(value, function(key, value) doPrint(key, value, space) end)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
if type(value) == 'string' then
|
||||||
|
value = '[[' .. tostring(value) .. ']]'
|
||||||
|
end
|
||||||
|
print(space .. key .. '=' .. tostring(value))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
doPrint(name, tab)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function clone(t)
|
||||||
|
local ret = {}
|
||||||
|
for k,v in pairs(t) do
|
||||||
|
ret[k] = v
|
||||||
|
end
|
||||||
|
return ret
|
||||||
|
end
|
||||||
|
|
||||||
|
local function inner_merge(t, remaining, from, ...)
|
||||||
|
if remaining == 0 then
|
||||||
|
return t
|
||||||
|
end
|
||||||
|
if from then
|
||||||
|
for k,v in pairs(from) do
|
||||||
|
t[k] = v
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return inner_merge(t, remaining - 1, ...)
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[*
|
||||||
|
Shallow-merges tables in order onto the first table.
|
||||||
|
|
||||||
|
@param t table to merge entries onto
|
||||||
|
@param ... sequence of 0 or more tables to merge onto 't'
|
||||||
|
|
||||||
|
@returns table 't' from input
|
||||||
|
]]
|
||||||
|
local function merge(t, ...)
|
||||||
|
return inner_merge(t, select('#', ...), ...)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Function to insert nulls into the JSON stream
|
||||||
|
local function null()
|
||||||
|
return null
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Marker for 'undefined' values
|
||||||
|
local function undefined()
|
||||||
|
return undefined
|
||||||
|
end
|
||||||
|
|
||||||
|
local ArrayMT = {}
|
||||||
|
|
||||||
|
--[[
|
||||||
|
Return's true if the metatable marks it as an array..
|
||||||
|
Or false if it has no array component at all
|
||||||
|
Otherwise nil to get the normal detection component working
|
||||||
|
]]
|
||||||
|
local function IsArray(value)
|
||||||
|
if type(value) ~= 'table' then return false end
|
||||||
|
local meta = getmetatable(value)
|
||||||
|
local ret = meta == ArrayMT or (meta ~= nil and meta.__is_luajson_array)
|
||||||
|
if not ret then
|
||||||
|
if #value == 0 then return false end
|
||||||
|
else
|
||||||
|
return ret
|
||||||
|
end
|
||||||
|
end
|
||||||
|
local function InitArray(array)
|
||||||
|
setmetatable(array, ArrayMT)
|
||||||
|
return array
|
||||||
|
end
|
||||||
|
|
||||||
|
local CallMT = {}
|
||||||
|
|
||||||
|
local function isCall(value)
|
||||||
|
return CallMT == getmetatable(value)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function buildCall(name, ...)
|
||||||
|
local callData = {
|
||||||
|
name = name,
|
||||||
|
parameters = {n = select('#', ...), ...}
|
||||||
|
}
|
||||||
|
return setmetatable(callData, CallMT)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function decodeCall(callData)
|
||||||
|
if not isCall(callData) then return nil end
|
||||||
|
return callData.name, callData.parameters
|
||||||
|
end
|
||||||
|
|
||||||
|
local function doOptionMerge(options, nested, name, defaultOptions, modeOptions)
|
||||||
|
if nested then
|
||||||
|
modeOptions = modeOptions and modeOptions[name]
|
||||||
|
defaultOptions = defaultOptions and defaultOptions[name]
|
||||||
|
end
|
||||||
|
options[name] = merge(
|
||||||
|
{},
|
||||||
|
defaultOptions,
|
||||||
|
modeOptions,
|
||||||
|
options[name]
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
local json_util = {
|
||||||
|
printValue = printValue,
|
||||||
|
clone = clone,
|
||||||
|
merge = merge,
|
||||||
|
null = null,
|
||||||
|
undefined = undefined,
|
||||||
|
IsArray = IsArray,
|
||||||
|
InitArray = InitArray,
|
||||||
|
isCall = isCall,
|
||||||
|
buildCall = buildCall,
|
||||||
|
decodeCall = decodeCall,
|
||||||
|
doOptionMerge = doOptionMerge
|
||||||
|
}
|
||||||
|
|
||||||
|
return json_util
|
95
tools/luajson/test_json.lua
Normal file
95
tools/luajson/test_json.lua
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
package.path = package.path .. ";lua_scripts/libraries/luajson/?.lua"
|
||||||
|
|
||||||
|
local JSON = require"json"
|
||||||
|
|
||||||
|
local jsontest = [[{ 1:{"scn_ptz_id":"",
|
||||||
|
"scn_ptz_prepos":"Preset 176",
|
||||||
|
"scn_ptz_order":1,
|
||||||
|
"scn_ptz_duration":"30",
|
||||||
|
"scn_ptz_rally_delay":"2"}
|
||||||
|
,
|
||||||
|
2:{"scn_ptz_id":"","scn_ptz_prepos":"route","scn_ptz_order":2,"scn_ptz_duration":"30","scn_ptz_rally_delay":"2"} }
|
||||||
|
]]
|
||||||
|
local jsontest2 = [[{
|
||||||
|
"extension":"mpg",
|
||||||
|
"id":1545148451781,
|
||||||
|
"name":"Foule_1280x720p.mpg",
|
||||||
|
"size":67240746,
|
||||||
|
"date":1545148451,
|
||||||
|
"mime":"video\/mpeg",
|
||||||
|
"filename":"1545148451781.mpg",
|
||||||
|
"dir":"\/home\/pixalarm_data\/fileprocessor_data",
|
||||||
|
"function_metadatas":
|
||||||
|
{
|
||||||
|
"function_faceblur":
|
||||||
|
{
|
||||||
|
"date":1545228627,
|
||||||
|
"current_frame":"845",
|
||||||
|
"polygons":[
|
||||||
|
{
|
||||||
|
"polygon_id":"new_1",
|
||||||
|
"polygon_vertex":"[
|
||||||
|
[0.14254859611231102,0.12476007677543186],[0.13174946004319654,0.4740882917466411],
|
||||||
|
[0.3898488120950324,0.6621880998080614],[0.4038876889848812,0.11516314779270634]
|
||||||
|
]",
|
||||||
|
"polygon_frame_start":"1",
|
||||||
|
"polygon_frame_stop":"300",
|
||||||
|
"polygon_type":"full_blur"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"polygon_id":"new_2",
|
||||||
|
"polygon_vertex":"[
|
||||||
|
[0.6198704103671706,0.1727447216890595],[0.5496760259179265,0.6007677543186181],
|
||||||
|
[0.7775377969762419,0.7946257197696737],[0.9028077753779697,0.761996161228407],
|
||||||
|
[0.9481641468682506,0.2821497120921305],[0.7829373650107991,0.04798464491362764]
|
||||||
|
]",
|
||||||
|
"polygon_frame_start":"200",
|
||||||
|
"polygon_frame_stop":"845",
|
||||||
|
"polygon_type":"no_blur"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"framecuts":[
|
||||||
|
["17","110"],
|
||||||
|
["248","298"],
|
||||||
|
["488","620"],
|
||||||
|
["378","428"]
|
||||||
|
],
|
||||||
|
"face_selection":[
|
||||||
|
{
|
||||||
|
"frame":"21",
|
||||||
|
"x":"0.5",
|
||||||
|
"y":"0.356"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"frame":"108",
|
||||||
|
"x":"0.4289",
|
||||||
|
"y":"0.275"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"frame":"294",
|
||||||
|
"x":"0.726",
|
||||||
|
"y":"0.2364"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"blur_type":"blur",
|
||||||
|
"blur_area":"face"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"total_frame":"845",
|
||||||
|
"status":"DECODE_FINISHED",
|
||||||
|
"fps":"25.00"
|
||||||
|
}]]
|
||||||
|
|
||||||
|
local res = JSON.decode(jsontest2)
|
||||||
|
for k, v in pairs(res) do
|
||||||
|
print( k, v)
|
||||||
|
end
|
||||||
|
|
||||||
|
res = JSON.decode( '{"content" : {},"date" : "2014-12-30T08:29:48Z","error" : {"code" : 0,"httpcode" : 200,"message" : ""},"status" : 1}' )
|
||||||
|
for k, v in pairs(res) do
|
||||||
|
print( k, v)
|
||||||
|
end
|
||||||
|
|
||||||
|
local jsondata = JSON.encode( res )
|
||||||
|
print(jsondata)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user