<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Semantic JSON</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div id="here">
</div>
<script>
// 3 objects.
// We tag keys with types. Types come first between angle brackets.
x= {
"<relation>ownership": {
"<slot>owner": "<person>Janis",
"<slot>owned": "<vehicle>Mercedes"
}
};
y= [
"<behavior>select",
"<behavior>open the door",
[
"<behavior>sequence",
"<behavior>unlock the door",
"<behavior>open the door"
]
];
z= {
"<name>name": "John Doe",
"<years>age": 32,
"<job>occupation": "developer",
"<people>siblings": [
"Arthur Doe",
"Sarah Doe"
],
"<lifeFormParents>parents": {
"<person>father": "Homer Doe",
"<person>mother": "Ema Doe"
}
};
// That's our proxy handler.
handler = {
get (target, key) {
var keys = Object.keys(target);
for (var k in keys) {
if (keys[k][0] === "<") {
var tagsend = keys[k].search(">");
if (key === keys[k].substring(tagsend+1)) {
if (reactOnGet[keys[k].substring(1,tagsend)])
reactOnGet[keys[k].substring(1,tagsend)](key,target[keys[k]]);
if (typeof target[keys[k]] === 'object')
return new Proxy(target[keys[k]],handler);
else
return target[keys[k]];
}
}
}
}
}
// This is our "get" reactor. We could do the same on "set" or any other proxy trap.
reactOnGet = {
relation: function(key,val) {
console.log(`read a relation, key:${key}`);
},
slot: function(key,val) {
console.log(`read a slot, val:${val}`);
}
}
// We set a proxy on x.
var px = new Proxy (x, handler);
// We're ready to access its members.
document.getElementById('here').innerHTML = px.ownership.owned;
</script>
</body>
</html>
console.log("read a relation, key: "+key);
console.log("read a slot, val: "+val);
<script>
// the global proxy manager
globalProxy = {
handler: {
get (target, key, receiver) {
// if we have a reaction, react
if ((typeof target !== 'function') && (target['<tag>'+key]))
if (globalProxy.react.onGet[target['<tag>'+key]])
globalProxy.react.onGet[target['<tag>'+key]](key, target[key]);
return target[key];
},
set (target, key, value, receiver) {
target[key.strPart] = globalProxy.prepare(value, true);
// keep tag for later use
Object.defineProperty(target, '<tag>'+key.strPart, {
enumerable: false,
value: key.tagPart
});
// if we have a reaction, react
if (globalProxy.react.onSet[key.tagPart])
globalProxy.react.onSet[key.tagPart](key, target[key.strPart]);
},
apply (target, thisArg, argList) {
// an id to match before-call and after-call
var callId = Symbol();
var haveReaction = (
thisArg['<tag>'+Object.keys(thisArg)[0]]
in
globalProxy.react.onApply);
if (haveReaction)
globalProxy.react.onApply[thisArg['<tag>'+Object.keys(thisArg)[0]]](
Object.keys(thisArg)[0],
thisArg,
argList,
false, // is call done yet?
callId);
var result = Reflect.apply(...arguments);
if (haveReaction)
globalProxy.react.onApply[thisArg['<tag>'+Object.keys(thisArg)[0]]](
Object.keys(thisArg)[0],
thisArg,
argList,
true, // is call done yet?
callId);
return result;
}
},
// recursively prepare an object, making a proxy out of it
prepare: function (obj) {
if (typeof obj === 'function') return new Proxy(obj, globalProxy.handler);
if (typeof obj !== 'object') return obj;
var result = {};
var keys = Object.keys(obj);
for (var k=0; k<keys.length; k++) {
result[keys[k].strPart] = globalProxy.prepare(obj[keys[k]]);
// keep tag for later use
Object.defineProperty(result, '<tag>'+keys[k].strPart, {
enumerable: false,
value: keys[k].tagPart
});
}
return new Proxy(result, globalProxy.handler);
},
// proxy traps reactor
react: {
onGet: {
// for every <relation> tag
relation: function(key, val) {
console.log(`reading a relation, key:${key}`);
},
// for every <slot> tag
slot: function(key, val) {
console.log(`reading a slot, val:${val}`);
}
},
onSet: {
},
onApply: {
// for every <math> tag
math: function(key, thisArg, argList, done, callId) {
var al = JSON.stringify(argList);
var when = done ? 'after' : 'before';
console.log(`${when} calling a math function, arguments:${al}`);
}
}
}
};
// a global getter to create objects
Object.defineProperty((window || global), 'object', { get : function() {
return globalProxy.prepare({});
}});
// get the "tag" part of a string
Object.defineProperty(String.prototype, 'tagPart', { get : function() {
if (this[0] !== '<')
return '';
else {
var tagsEnd = this.search('>');
if (tagsEnd < 0)
return '';
else
return this.substring(1, tagsEnd);
}
}});
// get the "str" part of a string
Object.defineProperty(String.prototype, 'strPart', { get : function() {
if (this[0] !== '<')
return this;
else {
var tagsEnd = this.search('>');
if (tagsEnd < 0)
return this;
else
return this.substring(tagsEnd+1);
}
}});
// check if string has tag
Object.defineProperty(String.prototype, 'hasTag', { get : function() {
return ((this[0] === '<') && (this.search('>') > -1));
}});
// register a hook
function sense(event, tag, reaction) {
globalProxy.react[event][tag] = reaction;
}
// playground to test things
sense('onSet', 'slot', function(key, val) {
console.log(`setting a slot, val:${val}`);
});
workspace = object;
workspace.foo = {
"<relation>ownership": {
"<slot>owner": "<person>Janis",
"<slot>owned": "<vehicle>Porsche"
}
};
workspace.foo.ownership["<slot>owned"] = "<vehicle>Mercedes";
document.getElementById('here').innerHTML = JSON.stringify(workspace.foo.ownership);
workspace.fun = {
"<math>add": function(a, b) { return a+b; },
"<math>mul": function(a, b) {
workspace.foo["<slot>result"] = 0;
for (var i=0; i<b; i++)
workspace.foo["<slot>result"] =
workspace.fun.add(a,workspace.foo.result);
return workspace.foo.result;
}
};
document.getElementById('here').innerHTML += '<br>'+workspace.fun.mul(3,4);
document.getElementById('here').innerHTML += '<br>'+workspace.foo["<tag>ownership"];
</script>
it needs a motivation yet?Sorry, I didn't understand.
workspace.foo = {
"ownership": {
"owner": "Janis",
"owned": "Mercedes"
}
}
workspace.foo = {
"<relation>ownership": {
"<slot>owner": "<person>Janis",
"<slot>owned": "<vehicle>Mercedes"
}
};
namespace prefix : "filename"
item name -> [ meta | data ]
item name -> relation type { slot1: item1, item2, ... ; slot2: item3; }
item name -> ( behavior node, ... , ... )
function log(x) { console.log(JSON.stringify(x)); }
var entity = {};
entity.externalSensors = [0, 0, 0, 0, 0, 0, 0, 0];
entity.externalActuators = [0, 0, 0, 0];
entity.internalSensors = [0, 0, 0, 0];
entity.instantMemory = [
[0, 4, 4, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
];
entity.target = [18, 1, 2, 3];
entity.behavior = {
3: [0, 2, 3, 0],
5: [0, 1, 0, 0],
8: [1, 0, 2, 0]
}
entity.setActuator = function(actuatorId, newValue) {
entity.externalActuators[actuatorId] = newValue;
entity.internalSensors = [0, actuatorId, newValue, 0];
}
entity.refreshInstantMemory = function() {
entity.instantMemory.push(
entity.externalSensors
.concat(entity.internalSensors)
.concat(entity.externalActuators)
);
entity.instantMemory.shift();
}
entity.logInstantMemory = function() {
for (var i=0; i<entity.instantMemory.length; i++)
console.log(JSON.stringify(entity.instantMemory[i]));
console.log();
}
entity.setTarget = function(targetSlot, newAddress) {
entity.target[targetSlot] = newAddress;
entity.internalSensors = [1, targetSlot, newAddress, 0];
}
entity.xy = function(n) { return { x: n%16, y: Math.floor(n/16) }; }
entity.fetch = function() {
var values = [];
for (var t=0; t<4; t++) {
var addr = entity.xy(entity.target[t]);
values.push(entity.instantMemory[addr.y][addr.x]);
}
return values
}
entity.interpret = function(values) {
var candidate = 0;
for (var i1=0; i1<3; i1++) {
for (var i2=i1+1; i2<4; i2++) {
if ((values[i1]==values[i2]) && (values[i1]>candidate))
candidate = values[i1];
}
}
return candidate*2;
}
entity.do = function(action) {
if (action[0]==0) setActuator(action[1], action[2]);
if (action[0]==1) setTarget(action[1], action[2]);
}
entity.run = function() {
while (1) {
entity.refreshInstantMemory();
entity.do(
entity.behavior[
entity.interpret(
entity.fetch())]);
}
}
entity.run();
// good call, we have 1 variable and 1 constant:
workspace.fun.mul(workspace.foo.x, 3);
// bad call, we have a sum and a constant:
workspace.fun.mul(workspace.foo.x + workspace.foo.y, 3);
{"int a" : "4"}