summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--content/encyclopediae/base.json14
-rw-r--r--content/encyclopediae/crops.json76
-rw-r--r--content/encyclopediae/default_encyclopedia.json70
-rw-r--r--content/encyclopediae/npcs.json64
-rw-r--r--src/assemblage.rs63
-rw-r--r--src/errors.rs20
-rw-r--r--src/fromtoparameter.rs11
-rw-r--r--src/item.rs11
-rw-r--r--src/main.rs2
-rw-r--r--src/parameter.rs114
-rw-r--r--src/parameterexpression.rs179
-rw-r--r--src/template.rs15
12 files changed, 244 insertions, 395 deletions
diff --git a/content/encyclopediae/base.json b/content/encyclopediae/base.json
index e6806b5..1964579 100644
--- a/content/encyclopediae/base.json
+++ b/content/encyclopediae/base.json
@@ -23,7 +23,7 @@
"grass": {
"components": [
["Visible", {
- "sprite": ["random", [
+ "sprite": {"$random": [
"grass1",
"grass2",
"grass3",
@@ -31,7 +31,7 @@
"grass2",
"grass3",
"ground"
- ]],
+ ]},
"height": 0.1,
"name": "grass"
}]
@@ -41,11 +41,11 @@
"greengrass": {
"components": [
["Visible", {
- "sprite": ["random", [
+ "sprite": {"$random": [
"grass1",
"grass2",
"grass3"
- ]],
+ ]},
"height": 0.1,
"name": "grass"
}]
@@ -76,14 +76,14 @@
"img": {
"arguments": [["sprite", "string", ""], ["height", "float", 1.0]],
"components": [
- ["Visible", {"name": ["arg", "sprite"], "sprite": ["arg", "sprite"], "height": ["arg", "height"]}]
+ ["Visible", {"name": {"$arg": "sprite"}, "sprite": {"$arg": "sprite"}, "height": {"$arg": "height"}}]
]
},
"letter": {
"arguments": [["char", "string"]],
"components": [["Visible", {
- "name": ["concat", ["letter_", ["arg", "char"]]],
- "sprite": ["concat", ["emptyletter-", ["arg", "char"]]],
+ "name": {"$concat": ["letter_", {"$arg": "char"}]},
+ "sprite": {"$concat": ["emptyletter-", {"$arg": "char"}]},
"height": 1.0
}]]
}
diff --git a/content/encyclopediae/crops.json b/content/encyclopediae/crops.json
index a8c9047..0c16073 100644
--- a/content/encyclopediae/crops.json
+++ b/content/encyclopediae/crops.json
@@ -6,12 +6,12 @@
"height": 0.5,
"components": [
["Interactable", {"typ": "trigger", "arg": "die"}],
- ["Loot", {"loot": ["list", [
- ["list", [{"type": "radishseed"}, 0.92]],
- ["list", [{"type": "radishseed"}, 0.20]],
- ["list", [{"type": "radish"}, 0.8]],
- ["list", [{"type": "radish"}, 0.4]]
- ]]}]
+ ["Loot", {"loot": [
+ [{"$template": "radishseed"}, 0.92],
+ [{"$template": "radishseed"}, 0.20],
+ [{"$template": "radish"}, 0.8],
+ [{"$template": "radish"}, 0.4]
+ ]}]
],
"flags": ["Occupied"]
},
@@ -24,10 +24,10 @@
["Timer", {
"delay": 600,
"spread": 0.5,
- "target_time": ["arg", "target_time"],
+ "target_time": {"$arg": "target_time"},
"trigger": "change"
}],
- ["Build", {"obj": ["template", "radishseedling"]}]
+ ["Build", {"obj": {"$template": "radishseedling"}}]
],
"extract": {
"target_time": ["Timer", "target_time"]
@@ -43,10 +43,10 @@
["Timer", {
"delay": 600,
"spread": 0.5,
- "target_time": ["arg", "target_time"],
+ "target_time": {"$arg": "target_time"},
"trigger": "change"
}],
- ["Build", {"obj": ["template", "youngradishplant"]}]
+ ["Build", {"obj": {"$template": "youngradishplant"}}]
],
"extract": {
"target_time": ["Timer", "target_time"]
@@ -62,10 +62,10 @@
["Timer", {
"delay": 600,
"spread": 0.5,
- "target_time": ["arg", "target_time"],
+ "target_time": {"$arg": "target_time"},
"trigger": "change"
}],
- ["Build", {"obj": ["template", "radishplant"]}]
+ ["Build", {"obj": {"$template": "radishplant"}}]
],
"extract": {
"target_time": ["Timer", "target_time"]
@@ -79,12 +79,12 @@
"name": "plantedseed",
"components": [
["Timer", {
- "delay": ["arg", "delay"],
+ "delay": {"$arg": "delay"},
"spread": 0.5,
- "target_time": ["arg", "target_time"],
+ "target_time": {"$arg": "target_time"},
"trigger": "change"
}],
- ["Build", {"obj": ["arg", "next"]}]
+ ["Build", {"obj": {"$arg": "next"}}]
],
"extract": {
"target_time": ["Timer", "target_time"]
@@ -98,12 +98,12 @@
"name": "seedling",
"components": [
["Timer", {
- "delay": ["arg", "delay"],
+ "delay": {"$arg": "delay"},
"spread": 0.5,
- "target_time": ["arg", "target_time"],
+ "target_time": {"$arg": "target_time"},
"trigger": "change"
}],
- ["Build", {"obj": ["arg", "next"]}]
+ ["Build", {"obj": {"$arg": "next"}}]
],
"extract": {
"target_time": ["Timer", "target_time"]
@@ -114,14 +114,14 @@
"arguments": [["target_time", "int", -1], ["next", "template"], ["crop", "string"], ["delay", "int"]],
"components": [
["Timer", {
- "delay": ["arg", "delay"],
+ "delay": {"$arg": "delay"},
"spread": 0.5,
- "target_time": ["arg", "target_time"],
+ "target_time": {"$arg": "target_time"},
"trigger": "change"
}],
- ["Build", {"obj": ["arg", "next"]}],
+ ["Build", {"obj": {"$arg": "next"}}],
["Visible", {
- "name": ["concat", [["string", "young"], ["arg", "crop"], ["string", "plant"]]],
+ "name": {"$concat": ["young", {"$arg": "crop"}, "plant"]},
"sprite": "youngplant",
"height": 0.8
}]
@@ -137,10 +137,10 @@
"height": 1.0,
"components": [
["Interactable", {"typ": "trigger", "arg": "die"}],
- ["Loot", {"loot": ["list", [
- ["list", [{"type": "carrotseed"}, 1.0]],
- ["list", [{"type": "carrot"}, 1.0]]
- ]]}]
+ ["Loot", {"loot": [
+ [{"$template": "carrotseed"}, 1.0],
+ [{"$template": "carrot"}, 1.0]
+ ]}]
],
"flags": ["Occupied"]
},
@@ -150,12 +150,12 @@
"height": 1.0,
"components": [
["Interactable", {"typ": "trigger", "arg": "die"}],
- ["Loot", {"loot": ["list", [
- ["list", [{"type": "cottonseed"}, 0.92]],
- ["list", [{"type": "cottonseed"}, 0.20]],
- ["list", [{"type": "cotton"}, 0.8]],
- ["list", [{"type": "cotton"}, 0.4]]
- ]]}]
+ ["Loot", {"loot": [
+ [{"$template": "cottonseed"}, 0.92],
+ [{"$template": "cottonseed"}, 0.20],
+ [{"$template": "cotton"}, 0.8],
+ [{"$template": "cotton"}, 0.4]
+ ]}]
],
"flags": ["Occupied"]
},
@@ -176,11 +176,11 @@
"cottoncloth": {"sprite": "cottoncloth"}
},
"templates":{
- "plantedcarrotseed": ["plantedseed", {"delay": 1800, "next": {"type": "carrotseedling"}}],
- "carrotseedling": ["seedling", {"delay": 3000, "next": {"type": "youngcarrotplant"}}],
- "youngcarrotplant": ["youngplant", {"crop": "carrot", "delay": 6000, "next": {"type": "carrotplant"}}],
- "plantedcottonseed": ["plantedseed", {"delay": 6000, "next": {"type": "cottonseedling"}}],
- "cottonseedling": ["seedling", {"delay": 18000, "next": {"type": "youngcottonplant"}}],
- "youngcottonplant": ["youngplant", {"crop": "cotton", "delay": 36000, "next": {"type": "cottonplant"}}]
+ "plantedcarrotseed": ["plantedseed", {"delay": 1800, "next": {":template": "carrotseedling"}}],
+ "carrotseedling": ["seedling", {"delay": 3000, "next": {":template": "youngcarrotplant"}}],
+ "youngcarrotplant": ["youngplant", {"crop": "carrot", "delay": 6000, "next": {":template": "carrotplant"}}],
+ "plantedcottonseed": ["plantedseed", {"delay": 6000, "next": {":template": "cottonseedling"}}],
+ "cottonseedling": ["seedling", {"delay": 18000, "next": {":template": "youngcottonplant"}}],
+ "youngcottonplant": ["youngplant", {"crop": "cotton", "delay": 36000, "next": {":template": "cottonplant"}}]
}
}
diff --git a/content/encyclopediae/default_encyclopedia.json b/content/encyclopediae/default_encyclopedia.json
index 25e3d32..cf58771 100644
--- a/content/encyclopediae/default_encyclopedia.json
+++ b/content/encyclopediae/default_encyclopedia.json
@@ -3,25 +3,25 @@
"portal": {
"arguments": [["destination", "string"], ["destpos", "string", ""]],
"components": [
- ["RoomExit", {"destination": ["arg", "destination"], "dest_pos": ["arg", "destpos"]}]
+ ["RoomExit", {"destination": {"$arg": "destination"}, "dest_pos": {"$arg": "destpos"}}]
],
"flags": ["Floor"]
},
"_homeportal": {
- "arguments": [["allowed", "list", ["list", []]]],
+ "arguments": [["allowed", "list", []]],
"extract": {"allowed": ["Whitelist", "allowed"]},
"components": [
["RoomExit", {"destination": "_home+{player}", "dest_pos": ""}],
["Interactable", {"typ": "visit", "arg": "_home+{player}"}],
- ["Whitelist", {"allowed": ["arg", "allowed"]}]
+ ["Whitelist", {"allowed": {"$arg": "allowed"}}]
],
"flags": ["Floor"]
},
"builtwall": {
"arguments": [["health", "int", 100]],
"components": [
- ["Health", {"health": ["arg", "health"], "maxhealth": 100}],
- ["Loot", {"loot": ["list", [["list", [{"type": "stone"}, 1.0]]]]}]
+ ["Health", {"health": {"$arg": "health"}, "maxhealth": 100}],
+ ["Loot", {"loot": [[{"$template": "stone"}, 1.0]]}]
],
"sprite": "builtwall",
"height": 2,
@@ -38,7 +38,7 @@
"sprite": "dummy",
"height": 1,
"components": [
- ["Health", {"health": ["arg", "health"], "maxhealth": 20}]
+ ["Health", {"health": {"$arg": "health"}, "maxhealth": 20}]
]
},
"wound": {
@@ -51,16 +51,16 @@
"arguments": [["template", "template"], ["amount", "int", 1], ["delay", "int", 0], ["clan", "string", ""], ["initial_spawn", "bool", true], ["radius", "int", 0]],
"components": [
["Timer", {
- "delay": ["arg", "delay"],
+ "delay": {"$arg": "delay"},
"spread": 0.1,
"trigger": "spawn",
- "target_time": ["if", [["arg", "initial_spawn"], 0, -1]]
+ "target_time": {"$if": [{"$arg": "initial_spawn"}, 0, -1]}
}],
["Spawner", {
- "template": ["arg", "template"],
- "amount": ["arg", "amount"],
- "clan": ["arg", "clan"],
- "radius": ["arg", "radius"]
+ "template": {"$arg": "template"},
+ "amount": {"$arg": "amount"},
+ "clan": {"$arg": "clan"},
+ "radius": {"$arg": "radius"}
}]
]
},
@@ -68,9 +68,9 @@
"arguments": [["ent", "template"], ["clan", "string", ""]],
"components": [
["Spawner", {
- "template": ["arg", "ent"],
+ "template": {"$arg": "ent"},
"amount": 1,
- "clan": ["arg", "clan"],
+ "clan": {"$arg": "clan"},
"radius": 0
}],
["Timer", {
@@ -87,7 +87,7 @@
"flags": ["Blocking"],
"components": [
["Interactable", {"typ": "trigger", "arg": "change"}],
- ["Build", {"obj": {"type": "opendoor", "save": false}}]
+ ["Build", {"obj": {"$template": "opendoor", "__save__": false}}]
]
},
"opendoor": {
@@ -96,7 +96,7 @@
"flags": ["Occupied"],
"components": [
["Interactable", {"typ": "trigger", "arg": "change"}],
- ["Build", {"obj": {"type": "closeddoor", "save": false}}]
+ ["Build", {"obj": {"$template": "closeddoor", "__save__": false}}]
]
},
"sign": {
@@ -113,20 +113,15 @@
"components": [
["Interactable", {"typ": "mine", "arg": "mining"}],
["Minable", {"total": 20, "trigger": "loot"}],
- ["Loot", {"loot": ["list", [
- ["list", [{"type": "stone"}, 1.0]]
- ]]}]
+ ["Loot", {"loot": [[{"$template": "stone"}, 1.0]]}]
]
},
"spinningwheel": {
"sprite": "spinningwheel",
"height": 1.0,
"components": [
- ["Interactable", {"typ": "exchange", "arg": ["list", [
- "spin ",
- ["list", [
- ["list", ["cotton yarn", ["list", ["cotton", "cotton"]], ["list", ["cottonyarn"]]]]
- ]]
+ ["Interactable", {"typ": "exchange", "arg": ["spin ", [
+ ["cotton yarn", ["cotton", "cotton"], ["cottonyarn"]]
]]}]
]
},
@@ -134,11 +129,8 @@
"sprite": "loom",
"height": 1.0,
"components": [
- ["Interactable", {"typ": "exchange", "arg": ["list", [
- "weave ",
- ["list", [
- ["list", ["cotton cloth", ["list", ["cottonyarn", "cottonyarn", "cottonyarn", "cottonyarn", "cottonyarn"]], ["list", ["cottoncloth"]]]]
- ]]
+ ["Interactable", {"typ": "exchange", "arg": ["weave ", [
+ ["cotton cloth", ["cottonyarn", "cottonyarn", "cottonyarn", "cottonyarn", "cottonyarn"], ["cottoncloth"]]
]]}]
]
},
@@ -146,11 +138,8 @@
"sprite": "sewingtable",
"height": 1.0,
"components": [
- ["Interactable", {"typ": "exchange", "arg": ["list", [
- "sew ",
- ["list", [
- ["list", ["cape", ["list", ["cottoncloth", "cottoncloth", "cottoncloth", "cottonyarn", "cottonyarn"]], ["list", ["cape"]]]]
- ]]
+ ["Interactable", {"typ": "exchange", "arg": ["sew ", [
+ ["cape", ["cottoncloth", "cottoncloth", "cottoncloth", "cottonyarn", "cottonyarn"], ["cape"]]
]]}]
]
},
@@ -158,13 +147,10 @@
"sprite": "tub",
"height": 1.0,
"components": [
- ["Interactable", {"typ": "exchange", "arg": ["list", [
- "dye ",
- ["list", [
- ["list", ["red cape", ["list", ["cape", "reddye"]], ["list", ["redcape"]]]],
- ["list", ["green cape", ["list", ["cape", "greendye"]], ["list", ["greencape"]]]],
- ["list", ["blue cape", ["list", ["cape", "bluedye"]], ["list", ["bluecape"]]]]
- ]]
+ ["Interactable", {"typ": "exchange", "arg": ["dye ", [
+ ["red cape", ["cape", "reddye"], ["redcape"]],
+ ["green cape", ["cape", "greendye"], ["greencape"]],
+ ["blue cape", ["cape", "bluedye"], ["bluecape"]]
]]}]
]
}
@@ -239,6 +225,6 @@
}
},
"templates": {
- "homeportal": ["singleton", {"ent": {"type": "_homeportal"}}]
+ "homeportal": ["singleton", {"ent": {":template": "_homeportal"}}]
}
}
diff --git a/content/encyclopediae/npcs.json b/content/encyclopediae/npcs.json
index 592417c..5cb7a60 100644
--- a/content/encyclopediae/npcs.json
+++ b/content/encyclopediae/npcs.json
@@ -13,9 +13,9 @@
["Fighter", {"damage": 2, "cooldown": 6}],
["Movable", {"cooldown": 3}],
["Faction", {"faction": "evil"}],
- ["Loot", {"loot": ["list", [
- ["list", [{"type": "radishseed"}, 1.0]]
- ]]}]
+ ["Loot", {"loot": [
+ [{"$template": "radishseed"}, 1.0]
+ ]}]
]
},
"goblin": {
@@ -31,11 +31,11 @@
["Fighter", {"damage": 5, "cooldown": 8}],
["Movable", {"cooldown": 4}],
["Faction", {"faction": "evil"}],
- ["Loot", {"loot": ["list", [
- ["list", [{"type": "sword"}, 0.05]],
- ["list", [{"type": "club"}, 0.1]],
- ["list", [{"type": "radish"}, 0.25]]
- ]]}]
+ ["Loot", {"loot": [
+ [{"$template": "sword"}, 0.05],
+ [{"$template": "club"}, 0.1],
+ [{"$template": "radish"}, 0.25]
+ ]}]
]
},
"troll": {
@@ -51,13 +51,13 @@
["Fighter", {"damage": 15, "cooldown": 10}],
["Movable", {"cooldown": 5}],
["Faction", {"faction": "evil"}],
- ["Loot", {"loot": ["list", [
- ["list", [{"type": "stone"}, 1.0]],
- ["list", [{"type": "stone"}, 0.3]],
- ["list", [{"type": "pebble"}, 0.5]],
- ["list", [{"type": "pebble"}, 0.5]],
- ["list", [{"type": "pebble"}, 0.5]]
- ]]}]
+ ["Loot", {"loot": [
+ [{"$template": "stone"}, 1.0],
+ [{"$template": "stone"}, 0.3],
+ [{"$template": "pebble"}, 0.5],
+ [{"$template": "pebble"}, 0.5],
+ [{"$template": "pebble"}, 0.5]
+ ]}]
]
},
@@ -87,14 +87,11 @@
"height": 1.5,
"name": "crop trader",
"components": [
- ["Interactable", {"typ": "exchange", "arg": ["list", [
- "buy ",
- ["list", [
- ["list", ["pebble", ["list", ["radish", "radish"]], ["list", ["pebble"]]]],
- ["list", ["radishseed", ["list", ["radish"]], ["list", ["radishseed", "radishseed"]]]],
- ["list", ["carrotseed", ["list", ["radish"]], ["list", ["carrotseed"]]]],
- ["list", ["cottonseed", ["list", ["stone"]], ["list", ["cottonseed"]]]]
- ]]
+ ["Interactable", {"typ": "exchange", "arg": ["buy ", [
+ ["pebble", ["radish", "radish"], ["pebble"]],
+ ["radishseed", ["radish"], ["radishseed", "radishseed"]],
+ ["carrotseed", ["radish"], ["carrotseed"]],
+ ["cottonseed", ["stone"], ["cottonseed"]]
]]}],
["MonsterAI", {
"view_distance": 1,
@@ -109,13 +106,10 @@
"height": 1.5,
"name": "dye trader",
"components": [
- ["Interactable", {"typ": "exchange", "arg": ["list", [
- "buy ",
- ["list", [
- ["list", ["red dye", ["list", ["club", "club"]], ["list", ["reddye"]]]],
- ["list", ["green dye", ["list", ["stone", "stone", "stone", "stone", "stone"]], ["list", ["greendye"]]]],
- ["list", ["blue dye", ["list", ["sword"]], ["list", ["bluedye"]]]]
- ]]
+ ["Interactable", {"typ": "exchange", "arg": ["buy ", [
+ ["red dye", ["club", "club"], ["reddye"]],
+ ["green dye", ["stone", "stone", "stone", "stone", "stone"], ["greendye"]],
+ ["blue dye", ["sword"], ["bluedye"]]
]]}],
["MonsterAI", {
"view_distance": 1,
@@ -130,11 +124,8 @@
"height": 1.5,
"name": "toolsmith",
"components": [
- ["Interactable", {"typ": "exchange", "arg": ["list", [
- "buy ",
- ["list", [
- ["list", ["pickaxe", ["list", ["carrot", "carrot", "carrot", "carrot", "carrot", "carrot", "carrot", "carrot", "carrot", "carrot"]], ["list", ["pickaxe"]]]]
- ]]
+ ["Interactable", {"typ": "exchange", "arg": ["buy ", [
+ ["pickaxe", ["carrot", "carrot", "carrot", "carrot", "carrot", "carrot", "carrot", "carrot", "carrot", "carrot"], ["pickaxe"]]
]]}],
["MonsterAI", {
"view_distance": 1,
@@ -154,7 +145,8 @@
"move_chance": 0.01,
"homesickness": 0.3
}],
- ["Movable", {"cooldown": 3}]
+ ["Movable", {"cooldown": 3}],
+ ["Interactable", {"typ": "say", "arg": "Hello"}]
]
}
}
diff --git a/src/assemblage.rs b/src/assemblage.rs
index e4554eb..9911c77 100644
--- a/src/assemblage.rs
+++ b/src/assemblage.rs
@@ -181,9 +181,9 @@ mod tests {
],
"components": [
["Visible", {
- "sprite": ["arg", "sprite"],
- "height": ["float", 0.1],
- "name": ["string", "grass"]
+ "sprite": {"$arg": "sprite"},
+ "height": 0.1,
+ "name": "grass"
}]
]
})).unwrap();
@@ -210,9 +210,9 @@ mod tests {
],
"components": [
["visible", { // no capital so invalid
- "sprite": ["A", "sprite"],
- "height": ["float", 0.1],
- "name": ["string", "grass"]
+ "sprite": {"$arg": "sprite"},
+ "height": 0.1,
+ "name": "grass"
}]
]
})).unwrap_err();
@@ -229,48 +229,15 @@ mod tests {
],
"components": [
["Visible", {
- "sprite": ["A", "sprite"],
- "height": ["string", "0.1"],
- "name": ["string", "grass"]
+ "sprite": {"$arg": "sprite"},
+ "height": "0.1",
+ "name": "grass"
}]
]
})).unwrap_err();
// assert_eq!(result, "parameter type incorrect");
}
-// #[test]
- fn unknown_argument_name(){
- Assemblage::deserialize(&json!({
- "arguments": [
- ["sprite", "string", "grass1"]
- ],
- "components": [
- ["Visible", {
- "sprite": ["A", "sprits"],
- "height": ["float", 0.1],
- "name": ["string", "grass"]
- }]
- ]
- })).unwrap_err();
-// assert_eq!(result, "unknown argument name");
- }
-
-// #[test]
- fn wrong_argument_type(){
- Assemblage::deserialize(&json!({
- "arguments": [
- ["sprite", "int", 1]
- ],
- "components": [
- ["Visible", {
- "sprite": ["A", "sprite"],
- "height": ["float", 0.1],
- "name": ["string", "grass"]
- }]
- ]
- })).unwrap_err();
-// assert_eq!(result, "parameter type incorrect");
- }
@@ -282,9 +249,9 @@ mod tests {
],
"components": [
["Visible", {
- "sprite": ["A", "sprite"],
- "height": ["float", 0.1],
- "name": ["string", "grass"]
+ "sprite": {"$arg": "sprite"},
+ "height": 0.1,
+ "name": "grass"
}]
]
})).unwrap_err();
@@ -300,9 +267,9 @@ mod tests {
],
"components": [
["Visible", {
- "sprite": ["arg", "sprite"],
- "height": ["float", 0.1],
- "name": ["arg", "sprite"]
+ "sprite": {"$arg": "sprite"},
+ "height": 0.1,
+ "name": {"$arg": "sprite"}
}]
]
})).unwrap();
diff --git a/src/errors.rs b/src/errors.rs
index 294159c..c58f2ff 100644
--- a/src/errors.rs
+++ b/src/errors.rs
@@ -25,23 +25,3 @@ macro_rules! aerr {
}
-
-#[derive(Debug)]
-pub struct ParseError {
- pub text: String
-}
-impl Error for ParseError {
- fn source(&self) -> Option<&(dyn Error + 'static)> {
- None
- }
-}
-impl Display for ParseError {
- fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
- write!(f, "Error: {}", self.text)
- }
-}
-#[macro_export]
-macro_rules! perr {
- ($($description:tt)*) => {crate::errors::ParseError{text: format!($($description)*)}}
-}
-pub type PResult<T> = std::result::Result<T, ParseError>;
diff --git a/src/fromtoparameter.rs b/src/fromtoparameter.rs
index 8d169d0..13483d7 100644
--- a/src/fromtoparameter.rs
+++ b/src/fromtoparameter.rs
@@ -76,7 +76,6 @@ tofrom!(i64: Int);
tofrom!(f64: Float);
tofrom!(bool:Bool);
tofrom!(String: String);
-tofrom!(Pos: Pos);
tofrom!(Template: Template);
tofrom!(PlayerId(String));
@@ -177,3 +176,13 @@ where
Parameter::List(vec![self.0.to_parameter(), self.1.to_parameter(), self.2.to_parameter()])
}
}
+
+impl FromToParameter for Pos {
+ fn from_parameter(p: Parameter) -> Option<Self>{
+ let (x, y) = <(i64, i64)>::from_parameter(p)?;
+ Some(Self{x, y})
+ }
+ fn to_parameter(self) -> Parameter {
+ (self.x, self.y).to_parameter()
+ }
+}
diff --git a/src/item.rs b/src/item.rs
index 37ee4f2..c8337f9 100644
--- a/src/item.rs
+++ b/src/item.rs
@@ -1,7 +1,6 @@
use std::collections::HashSet;
-use std::str::FromStr;
use serde;
use serde::{Deserialize, Serialize};
use crate::{
@@ -9,8 +8,7 @@ use crate::{
components::{
Flag,
equipment::Equippable
- },
- errors::{ParseError}
+ }
};
@@ -18,13 +16,6 @@ use crate::{
#[derive(Debug, Default, PartialEq, Eq, Clone, Hash, Serialize, Deserialize)]
pub struct ItemId(pub String);
-impl FromStr for ItemId {
- type Err = ParseError;
- fn from_str(s: &str) -> Result<Self, Self::Err> {
- Ok(Self(s.to_string()))
- }
-}
-
#[derive(Debug, Clone)]
pub struct Item {
pub ent: Template,
diff --git a/src/main.rs b/src/main.rs
index 6cd0f24..2176801 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -45,7 +45,7 @@ use self::{
playerid::PlayerId,
roomid::RoomId,
item::ItemId,
- errors::{Result, PResult},
+ errors::{Result},
sprite::Sprite,
template::Template,
encyclopedia::Encyclopedia,
diff --git a/src/parameter.rs b/src/parameter.rs
index 29d1990..be846a1 100644
--- a/src/parameter.rs
+++ b/src/parameter.rs
@@ -1,35 +1,22 @@
-use serde_json::{Value, json};
-use serde::{de, Serialize, Deserialize, Serializer, Deserializer};
+use serde::{Serialize, Deserialize};
use strum_macros::{EnumString, Display};
use crate::{
Template,
- Pos,
- PResult,
- perr
};
macro_rules! parameters {
- ($($name: ident ($typ: ty) $stringname: ident, $v: ident ($fromjson: expr) ($tojson: expr));*;) => {
- #[derive(Debug, PartialEq, Clone)]
+ {$($name: ident $typ: ty);*;} => {
+ #[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
+ #[serde(untagged)]
pub enum Parameter {
$(
$name($typ),
)*
}
impl Parameter {
- pub fn from_typed_json(typ: ParameterType, val: &Value) -> PResult<Parameter>{
- match typ {
- $(
- ParameterType::$name => Ok(Self::$name({
- let $v = val;
- $fromjson
- })),
- )*
- }
- }
pub fn paramtype(&self) -> ParameterType {
match self {
$(
@@ -37,13 +24,6 @@ macro_rules! parameters {
)*
}
}
- pub fn to_json(&self) -> Value {
- match self {
- $(
- Self::$name($v) => $tojson,
- )*
- }
- }
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, EnumString, Display)]
@@ -54,36 +34,17 @@ macro_rules! parameters {
$name,
)*
}
- impl ParameterType {
- pub fn from_str(typename: &str) -> Option<Self>{
- match typename {
- $(
- stringify!($stringname) => Some(Self::$name),
- )*
- _ => None
- }
- }
- }
}
}
-parameters!(
- String (String) string, v (v.as_str().ok_or(perr!("{:?} not a string", v))?.to_string()) (json!(v));
- Int (i64) int, v (v.as_i64().ok_or(perr!("{:?} not an int", v))?) (json!(v));
- Pos (Pos) pos, v (Pos::deserialize(v).map_err(|e| perr!("{:?} not a pos {}", v, e))?) (json!(v));
- Float (f64) float, v (v.as_f64().ok_or(perr!("{:?} not an float", v))?) (json!(v));
- Template (Template) template, v (Template::deserialize(v).map_err(|e| perr!("template json error {:?}", e))?) (json!(["template", v]));
- Bool (bool) bool, v (v.as_bool().ok_or(perr!("{:?} not a bool", v))?) (json!(v));
- List (Vec<Parameter>) list, v
- ({
- v
- .as_array().ok_or(perr!("{:?} not an array", v))?
- .iter()
- .map(|item| Parameter::guess_from_json(item))
- .collect::<PResult<Vec<Parameter>>>()?
- })
- (json!(["list", v.iter().map(Parameter::to_json).collect::<Vec<Value>>()]));
-);
+parameters!{
+ String String;
+ Int i64;
+ Float f64;
+ Template Template;
+ Bool bool;
+ List Vec<Parameter>;
+}
impl Parameter {
@@ -92,58 +53,21 @@ impl Parameter {
Self::String(string.to_string())
}
- pub fn guess_from_json(val: &Value) -> PResult<Parameter> {
- if let Some(arr) = val.as_array() {
- if arr.len() == 2 && arr[0].is_string() {
- let typestr = arr[0].as_str().unwrap();
- let typ = ParameterType::from_str(typestr).ok_or(perr!("invalid parameter type {}", typestr))?;
- return Self::from_typed_json(typ, &arr[1]);
- }
- }
- let typ =
- if val.is_string() {
- ParameterType::String
- } else if val.is_u64() || val.is_i64() {
- ParameterType::Int
- } else if val.is_f64() {
- ParameterType::Float
- } else if val.is_boolean(){
- ParameterType::Bool
- } else if val.is_object(){
- ParameterType::Template
- } else {
- return Err(perr!("can't guess the type of parameter {:?}", val));
- };
- Self::from_typed_json(typ, val)
- }
}
-impl Serialize for Parameter {
- fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
- where S: Serializer {
- self.to_json().serialize(serializer)
- }
-}
-impl<'de> Deserialize<'de> for Parameter {
- fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
- where D: Deserializer<'de> {
- Self::guess_from_json(&Value::deserialize(deserializer)?).map_err(|e| de::Error::custom(e.text))
- }
-}
-
#[cfg(test)]
mod tests {
use super::*;
use serde_json::json;
macro_rules! gfj { // guess from json
- ($($j:tt)*) => {Parameter::guess_from_json(&json!($($j)*)).unwrap()}
+ ($($j:tt)*) => {Parameter::deserialize(&json!($($j)*)).unwrap()}
}
#[test]
fn can_guess_json() {
- Parameter::guess_from_json(&json!(3)).unwrap();
+ Parameter::deserialize(&json!(3)).unwrap();
}
#[test]
@@ -162,19 +86,19 @@ mod tests {
assert_eq!(gfj!(-0.0), Parameter::Float(0.0));
assert_eq!(gfj!(true), Parameter::Bool(true));
- assert_eq!(gfj!(["int", 3]), Parameter::Int(3));
+ assert_eq!(gfj!(["int", 3]), Parameter::List(vec![Parameter::string("int"), Parameter::Int(3)]));
+ assert_eq!(gfj!([2, 5]), Parameter::List(vec![Parameter::Int(2), Parameter::Int(5)]));
}
#[test]
fn guess_json_none() {
- assert!(Parameter::guess_from_json(&json!([2, 5])).is_err());
- assert!(Parameter::guess_from_json(&json!({"hello": "world"})).is_err());
+ assert!(Parameter::deserialize(&json!({"hello": "world"})).is_err());
}
#[test]
fn parse_list() {
assert_eq!(
- gfj!(["list", [5, 3, 1, 2]]),
+ gfj!([5, 3, 1, 2]),
Parameter::List(vec![
Parameter::Int(5),
Parameter::Int(3),
@@ -183,7 +107,7 @@ mod tests {
])
);
assert_eq!(
- gfj!(["list", [5, 3.0, "Hello", true]]),
+ gfj!([5, 3.0, "Hello", true]),
Parameter::List(vec![
Parameter::Int(5),
Parameter::Float(3.0),
diff --git a/src/parameterexpression.rs b/src/parameterexpression.rs
index b92613a..2db52ef 100644
--- a/src/parameterexpression.rs
+++ b/src/parameterexpression.rs
@@ -1,16 +1,13 @@
use std::collections::HashMap;
use rand::Rng;
-use serde_json::{Value, json};
-use serde::{Deserialize, Deserializer, de};
+use serde::{Deserialize, Deserializer};
use crate::{
parameter::{Parameter, ParameterType},
Template,
template::{EntityType},
Result as AnyResult,
aerr,
- PResult,
- perr
};
const MAX_NESTING: usize = 5;
@@ -21,7 +18,7 @@ pub enum ParameterExpression {
Constant(Parameter),
List(Vec<ParameterExpression>),
#[allow(dead_code)] // rustc bug does not know that this variant is used: https://github.com/rust-lang/rust/issues/68408
- Template{name: EntityType, kwargs: HashMap<String, ParameterExpression>, save: Option<bool>},
+ Template{name: EntityType, kwargs: HashMap<String, ParameterExpression>, save: Option<bool>, clan: Option<String>},
Argument(String),
Random(Vec<ParameterExpression>),
Concat(Vec<ParameterExpression>),
@@ -47,7 +44,7 @@ impl ParameterExpression {
Self::List(values) => {
Some(Parameter::List(values.iter().map(|v| v.evaluate_(arguments, template, nesting+1)).collect::<Option<Vec<Parameter>>>()?))
}
- Self::Template{name, kwargs, save} => {
+ Self::Template{name, kwargs, save, clan} => {
Some(Parameter::Template(Template{
name: name.clone(),
save: *save,
@@ -57,7 +54,7 @@ impl ParameterExpression {
|(k, v)|
Some((k.clone(), v.evaluate_(arguments, template, nesting+1)?)))
.collect::<Option<HashMap<String, Parameter>>>()?,
- clan: None
+ clan: clan.clone()
}))
}
Self::Argument(argname) => {
@@ -95,88 +92,12 @@ impl ParameterExpression {
}
}
- pub fn from_json(value: &Value) -> PResult<Self> {
- if !value.is_array() {
- return Ok(Self::Constant(Parameter::guess_from_json(value)?));
- }
- let paramvalue = value.get(1).ok_or(perr!("index 1 not in component parameter"))?;
- let typename = value.get(0).ok_or(perr!("index 0 not in component parameter"))?.as_str().ok_or(perr!("compparam type not a string"))?;
- match typename {
- "string" | "int" | "float" | "bool" | "pos" => {
- let paramtype = ParameterType::from_str(typename).expect(&format!("unknown parameter type {:?}", typename));
- Ok(Self::Constant(Parameter::from_typed_json(paramtype, paramvalue)?))
- }
- "list" => {
- let values = paramvalue.as_array().ok_or(perr!("random argument not an array"))?;
- let mut entries = Vec::new();
- for entry in values {
- entries.push(Self::from_json(entry)?)
- }
- Ok(Self::List(entries))
- }
- "template" => {
- match paramvalue {
- Value::String(s) => Ok(Self::Template{
- name: EntityType(s.clone()),
- kwargs: HashMap::new(),
- save: None
- }),
- Value::Object(o) => {
- let name = EntityType(o.get("type").ok_or(perr!("template doesn't have 'type'"))?.as_str().ok_or(perr!("template type not a string"))?.to_string());
- let mut kwargs = HashMap::new();
- for (key, arg) in o.get("kwargs").unwrap_or(&json!({})).as_object().ok_or(perr!("template kwargs not a json object"))? {
- kwargs.insert(key.to_string(), Self::from_json(arg)?);
- }
- let save = match o.get("save") {
- Some(Value::Bool(b)) if *b => Some(true),
- Some(Value::Bool(_b)) => Some(false),
- None => None,
- _ => {return Err(perr!("save not a bool"))}
- };
- Ok(Self::Template{name, kwargs, save})
- }
- _ => return Err(perr!("invalid template {:?}", paramvalue))
- }
- }
- "A" | "arg" => {
- let argname = paramvalue.as_str().ok_or(perr!("argument parameter not a string"))?.to_string();
- Ok(Self::Argument(argname))
- }
- "random" => {
- let optionvalues = paramvalue.as_array().ok_or(perr!("random argument not an array"))?;
- let mut options = Vec::new();
- for option in optionvalues {
- options.push(Self::from_json(option)?)
- }
- Ok(Self::Random(options))
- }
- "concat" => {
- let values = paramvalue.as_array().ok_or(perr!("concat argument not an array"))?;
- let mut options = Vec::new();
- for option in values {
- options.push(Self::from_json(option)?)
- }
- Ok(Self::Concat(options))
- }
- "if" => {
- Ok(Self::If(
- Box::new(Self::from_json(paramvalue.get(0).ok_or(perr!("if does not have condition"))?)?),
- Box::new(Self::from_json(paramvalue.get(1).ok_or(perr!("if does not have then value"))?)?),
- Box::new(Self::from_json(paramvalue.get(2).ok_or(perr!("if does not have else value"))?)?)
- ))
- }
- "self" => Ok(Self::TemplateSelf),
- "name" => Ok(Self::TemplateName),
- _ => Err(perr!("unknown compparam type '{}'", typename))
- }
- }
-
#[allow(dead_code)]
pub fn get_type(&self, arguments: &[(String, ParameterType, Option<Parameter>)]) -> AnyResult<ParameterType>{
Ok(match self {
Self::Constant(param) => param.paramtype(),
Self::List(_) => ParameterType::List,
- Self::Template{name: _, kwargs: _, save: _} => ParameterType::Template,
+ Self::Template{name: _, kwargs: _, save: _, clan: _} => ParameterType::Template,
Self::Argument(argname) => arguments.iter().find(|(n, _t, _d)| n == argname).ok_or(aerr!("unknown argument name {} in {:?}", argname, arguments))?.1,
Self::Random(options) => {
let typ: ParameterType = options.get(0).ok_or(aerr!("random has no options"))?.get_type(arguments)?;
@@ -204,16 +125,57 @@ impl ParameterExpression {
}
}
-// impl Serialize for ParameterExpression {
-// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
-// where S: Serializer {
-// self.to_json().serialize(serializer)
-// }
-// }
+
+#[derive(Debug, PartialEq, Clone, Deserialize)]
+enum DynamicParameterExpressionSave {
+ #[serde(rename = "$arg")]
+ Argument(String),
+ #[serde(rename = "$random")]
+ Random(Vec<ParameterExpression>),
+ #[serde(rename = "$concat")]
+ Concat(Vec<ParameterExpression>),
+ #[serde(rename = "$if")]
+ If(Box<ParameterExpression>, Box<ParameterExpression>, Box<ParameterExpression>),
+ #[serde(rename = "$self")]
+ TemplateSelf,
+ #[serde(rename = "$name")]
+ TemplateName
+}
+#[derive(Debug, PartialEq, Clone, Deserialize)]
+#[serde(untagged)]
+enum ParameterExpressionSave {
+ List(Vec<ParameterExpression>),
+ Template {
+ #[serde(rename = "$template")]
+ name: EntityType,
+ #[serde(rename="__save__", default, skip_serializing_if = "Option::is_none")]
+ save: Option<bool>,
+ #[serde(rename="__clan__", default, skip_serializing_if = "Option::is_none")]
+ clan: Option<String>,
+ #[serde(flatten)]
+ kwargs: HashMap<String, ParameterExpression>
+ },
+ Dynamic(DynamicParameterExpressionSave),
+ Constant(Parameter),
+}
+use ParameterExpressionSave as PES;
+use DynamicParameterExpressionSave as DPES;
+
impl<'de> Deserialize<'de> for ParameterExpression {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where D: Deserializer<'de> {
- Self::from_json(&Value::deserialize(deserializer)?).map_err(|e| de::Error::custom(e.text))
+ let save = ParameterExpressionSave::deserialize(deserializer)?;
+ Ok(match save {
+ PES::List(params) => Self::List(params),
+ PES::Template{name, save, clan, kwargs} => Self::Template{name, save, kwargs, clan},
+ PES::Dynamic(DPES::Argument(name)) => Self::Argument(name),
+ PES::Dynamic(DPES::Random(items)) => Self::Random(items),
+ PES::Dynamic(DPES::Concat(items)) => Self::Concat(items),
+ PES::Dynamic(DPES::If(condition, ifpart, elsepart)) => Self::If(condition, ifpart, elsepart),
+ PES::Dynamic(DPES::TemplateSelf) => Self::TemplateSelf,
+ PES::Dynamic(DPES::TemplateName) => Self::TemplateName,
+ PES::Constant(param) => Self::Constant(param)
+ })
}
}
@@ -222,6 +184,7 @@ mod tests {
use super::*;
use super::ParameterExpression as PE;
use crate::hashmap;
+ use serde_json::json;
#[test]
fn test_desrialize(){
@@ -230,22 +193,48 @@ mod tests {
PE::Constant(Parameter::String("hello".to_string()))
);
assert_eq!(
- PE::deserialize(json!(["arg", "hello"])).unwrap(),
+ PE::deserialize(json!({"$arg": "hello"})).unwrap(),
PE::Argument("hello".to_string())
);
assert_eq!(
- PE::deserialize(json!(["list", ["hello", 3]])).unwrap(),
+ PE::deserialize(json!(["hello", 3])).unwrap(),
PE::List(vec![
PE::Constant(Parameter::String("hello".to_string())),
PE::Constant(Parameter::Int(3))
])
);
+ }
+ #[test]
+ fn test_templates(){
assert_eq!(
- PE::deserialize(json!(["template", {"type": "radish", "kwargs": {"health": 10}}])).unwrap(),
+ PE::deserialize(json!({"$template": "radish", "health": 10})).unwrap(),
PE::Template{
name: EntityType("radish".to_string()),
kwargs: hashmap!{"health".to_string() => PE::Constant(Parameter::Int(10))},
- save: None
+ save: None,
+ clan: None
+ }
+ );
+ assert_eq!(
+ PE::deserialize(json!({":template": "radish", "health": 10})).unwrap(),
+ PE::Constant(Parameter::Template(Template{
+ name: EntityType("radish".to_string()),
+ kwargs: hashmap!{"health".to_string() => Parameter::Int(10)},
+ save: None,
+ clan: None
+ }))
+ );
+ assert_eq!(
+ PE::deserialize(json!({"$template": "radish", "health": {"$if": [{"$arg": "is_eldritch"}, 20, 3]}})).unwrap(),
+ PE::Template{
+ name: EntityType("radish".to_string()),
+ kwargs: hashmap!{"health".to_string() => PE::If(
+ Box::new(PE::Argument("is_eldritch".to_string())),
+ Box::new(PE::Constant(Parameter::Int(20))),
+ Box::new(PE::Constant(Parameter::Int(3)))
+ )},
+ save: None,
+ clan: None
}
);
}
diff --git a/src/template.rs b/src/template.rs
index 1ef6fc1..6eb27e1 100644
--- a/src/template.rs
+++ b/src/template.rs
@@ -23,6 +23,16 @@ enum TemplateSave {
save: Option<bool>,
#[serde(default, skip_serializing_if = "Option::is_none")]
clan: Option<String>
+ },
+ New{
+ #[serde(rename = ":template")]
+ name: EntityType,
+ #[serde(rename="__save__", default, skip_serializing_if = "Option::is_none")]
+ save: Option<bool>,
+ #[serde(rename="__clan__", default, skip_serializing_if = "Option::is_none")]
+ clan: Option<String>,
+ #[serde(default, flatten, skip_serializing_if = "HashMap::is_empty")]
+ kwargs: HashMap<String, Parameter>
}
}
@@ -40,7 +50,8 @@ impl From<TemplateSave> for Template {
fn from(ts: TemplateSave) -> Self {
match ts {
TemplateSave::Name(name) => Self{name, kwargs: HashMap::new(), save: None, clan: None},
- TemplateSave::Full{name, kwargs, save, clan} => Self{name, kwargs, save, clan}
+ TemplateSave::Full{name, kwargs, save, clan} => Self{name, kwargs, save, clan},
+ TemplateSave::New{name, kwargs, save, clan} => Self{name, kwargs, save, clan}
}
}
}
@@ -49,7 +60,7 @@ impl Into<TemplateSave> for Template {
if self.kwargs.is_empty() && self.save == None && self.clan == None {
return TemplateSave::Name(self.name);
}
- TemplateSave::Full {
+ TemplateSave::New {
name: self.name,
kwargs: self.kwargs,
save: self.save,