@cryptoeconomicslab/ovm-parser
Advanced tools
Comparing version 0.2.3 to 0.2.5
@@ -1,2 +0,2 @@ | ||
declare const text = "// OVM language grammar\n// ==========================\n//\n\n{\n\n}\n\nProgram\n = Declation*\n\nDeclation\n = \"def\" _ dec:Decider _ \":=\" _ s:Statement _ {\n return {\n name: dec.predicate,\n inputDefs: dec.inputs,\n body: s[0]\n }\n }\n\nStatement\n = expr:Expression tail:(Expression)*\n\nPredicate\n = UniversalQuantifier / ThereExistsQuantifier / NotPredicate / Decider\n\nNoArgs\n = \"(\" _ \")\" {\n return []\n }\n\nArgsExist\n = \"(\" arg:Arg args:(\",\" _ Arg)* \")\" {\n return [arg].concat(args.map((a) => a[2]))\n }\n\nArgs\n = ArgsExist / NoArgs\n\nDecider\n = name:String _ args:Args {\n return {\n type: 'PropertyNode',\n predicate: name,\n inputs: args\n }\n}\n \nUniversalQuantifier\n = V:Decider \".all(\" v:String _ \"->\" _ property:Expression _ \")\" {\n return {\n type: 'PropertyNode',\n predicate: \"ForAllSuchThat\",\n inputs: [\n V,\n v,\n property\n ]\n }\n }\n\nThereExistsQuantifier\n = Q:Decider \".any(\" v:String _ \"->\" _ property:Expression _ \")\" {\n return {\n type: 'PropertyNode',\n predicate: \"ThereExistsSuchThat\",\n inputs: [\n Q,\n v,\n property\n ]\n }\n }\n\nNotPredicate\n = \"!\" _ property:Factor {\n return {\n type: 'PropertyNode',\n predicate: \"Not\",\n inputs: [\n property\n ]\n }\n }\n\nExpression\n = head:Factor tail:(_ (\"and\" / \"or\") _ Factor)* {\n if(tail.length > 0) {\n const op = tail[0][1]\n const items = tail.map((t) => t[3])\n return {\n type: 'PropertyNode',\n predicate: op == \"and\" ? \"And\" : \"Or\",\n inputs: [head].concat(items)\n }\n } else {\n return head;\n }\n }\n\nFactor\n = \"(\" _ expr:Expression _ \")\" { return expr }\n / Predicate\n\nInteger \"integer\"\n = _ [0-9]+ { return parseInt(text(), 10); }\n\nArg\n = parent:String children:(\".\" (Integer / \"address\"))* {\n return parent + children.map(c => '.' + c[1]).join('')\n }\n\nString \"string\"\n = _ \"$\"?[a-zA-Z0-9_]+ { return text(); }\n\n_ \"whitespace\"\n = [ \\t\\n\\r]*\n"; | ||
declare const text = "// OVM language grammar\n// ==========================\n//\n{\n}\nProgram\n = _ i:Import* d:PropertyDeclaration* {\n return {\n imports: i,\n declarations: d\n }\n }\nImport\n = \"from\" _ path:String _ \"import\" _ module:String _ {\n return {\n path: path,\n module: module\n }\n }\nAnnotation\n = \"@\" _ body:(AnnotationBodyWithArgs / AnnotationBody) _ {\n return {\n type: 'Annotation',\n body: body\n }\n }\nAnnotationBody\n = name:String {\n return {\n name: name,\n args: []\n }\n }\nAnnotationBodyWithArgs\n = name:String \"(\" arg:ConstString \")\" {\n return {\n name: name,\n args: [arg]\n }\n }\nPropertyDeclaration\n = a:Annotation* _ \"def\" _ dec:Decider _ \":=\" _ s:Statement _ {\n return {\n name: dec.predicate,\n inputDefs: dec.inputs,\n body: s[0],\n annotations: a\n }\n }\nStatement\n = expr:Expression tail:(Expression)*\nPredicate\n = UniversalQuantifier / ThereExistsQuantifier / NotPredicate / Decider\nNoArgs\n = \"(\" _ \")\" {\n return []\n }\nArgsExist\n = \"(\" arg:Arg args:(\",\" _ Arg)* \")\" {\n return [arg].concat(args.map((a) => a[2]))\n }\nArgs\n = ArgsExist / NoArgs\nDecider\n = name:String _ args:Args {\n return {\n type: 'PropertyNode',\n predicate: name,\n inputs: args\n }\n}\n \nUniversalQuantifier\n = V:Decider \".all(\" v:String _ \"->\" _ property:Expression _ \")\" {\n return {\n type: 'PropertyNode',\n predicate: \"ForAllSuchThat\",\n inputs: [\n V,\n v,\n property\n ]\n }\n }\nThereExistsQuantifier\n = Q:Decider \".any(\" _ inner:InnerProperty? _ \")\" {\n let inputs = [Q]\n if(inner) inputs = inputs.concat(inner)\n return {\n type: 'PropertyNode',\n predicate: \"ThereExistsSuchThat\",\n inputs: inputs\n }\n }\nInnerProperty\n = v:String _ \"->\" _ property:Expression {\n return [v, property]\n }\nNotPredicate\n = \"!\" _ property:Factor {\n return {\n type: 'PropertyNode',\n predicate: \"Not\",\n inputs: [\n property\n ]\n }\n }\nExpression\n = head:Factor tail:(_ (\"and\" / \"or\") _ Factor)* {\n if(tail.length > 0) {\n const op = tail[0][1]\n const items = tail.map((t) => t[3])\n return {\n type: 'PropertyNode',\n predicate: op == \"and\" ? \"And\" : \"Or\",\n inputs: [head].concat(items)\n }\n } else {\n return head;\n }\n }\nFactor\n = \"(\" _ expr:Expression _ \")\" { return expr }\n / Predicate\nInteger \"integer\"\n = _ [0-9]+ { return parseInt(text(), 10); }\nArg\n = parent:String children:(\".\" (Integer / \"address\"))* {\n return parent + children.map(c => '.' + c[1]).join('')\n }\nString \"string\"\n = _ \"$\"?[a-zA-Z0-9_]+ { return text(); }\nConstString\n = _ \"\\\"\"str:([a-zA-Z0-9_.,\\-{}$]*)\"\\\"\" { return str.join(''); }\n_ \"whitespace\"\n = [ \\t\\n\\r]*\n"; | ||
export default text; |
@@ -6,25 +6,52 @@ "use strict"; | ||
// | ||
{ | ||
} | ||
Program | ||
= Declation* | ||
Declation | ||
= "def" _ dec:Decider _ ":=" _ s:Statement _ { | ||
= _ i:Import* d:PropertyDeclaration* { | ||
return { | ||
imports: i, | ||
declarations: d | ||
} | ||
} | ||
Import | ||
= "from" _ path:String _ "import" _ module:String _ { | ||
return { | ||
path: path, | ||
module: module | ||
} | ||
} | ||
Annotation | ||
= "@" _ body:(AnnotationBodyWithArgs / AnnotationBody) _ { | ||
return { | ||
type: 'Annotation', | ||
body: body | ||
} | ||
} | ||
AnnotationBody | ||
= name:String { | ||
return { | ||
name: name, | ||
args: [] | ||
} | ||
} | ||
AnnotationBodyWithArgs | ||
= name:String "(" arg:ConstString ")" { | ||
return { | ||
name: name, | ||
args: [arg] | ||
} | ||
} | ||
PropertyDeclaration | ||
= a:Annotation* _ "def" _ dec:Decider _ ":=" _ s:Statement _ { | ||
return { | ||
name: dec.predicate, | ||
inputDefs: dec.inputs, | ||
body: s[0] | ||
body: s[0], | ||
annotations: a | ||
} | ||
} | ||
Statement | ||
= expr:Expression tail:(Expression)* | ||
Predicate | ||
= UniversalQuantifier / ThereExistsQuantifier / NotPredicate / Decider | ||
NoArgs | ||
@@ -34,3 +61,2 @@ = "(" _ ")" { | ||
} | ||
ArgsExist | ||
@@ -40,6 +66,4 @@ = "(" arg:Arg args:("," _ Arg)* ")" { | ||
} | ||
Args | ||
= ArgsExist / NoArgs | ||
Decider | ||
@@ -66,16 +90,16 @@ = name:String _ args:Args { | ||
} | ||
ThereExistsQuantifier | ||
= Q:Decider ".any(" v:String _ "->" _ property:Expression _ ")" { | ||
= Q:Decider ".any(" _ inner:InnerProperty? _ ")" { | ||
let inputs = [Q] | ||
if(inner) inputs = inputs.concat(inner) | ||
return { | ||
type: 'PropertyNode', | ||
predicate: "ThereExistsSuchThat", | ||
inputs: [ | ||
Q, | ||
v, | ||
property | ||
] | ||
inputs: inputs | ||
} | ||
} | ||
InnerProperty | ||
= v:String _ "->" _ property:Expression { | ||
return [v, property] | ||
} | ||
NotPredicate | ||
@@ -91,3 +115,2 @@ = "!" _ property:Factor { | ||
} | ||
Expression | ||
@@ -107,10 +130,7 @@ = head:Factor tail:(_ ("and" / "or") _ Factor)* { | ||
} | ||
Factor | ||
= "(" _ expr:Expression _ ")" { return expr } | ||
/ Predicate | ||
Integer "integer" | ||
= _ [0-9]+ { return parseInt(text(), 10); } | ||
Arg | ||
@@ -120,6 +140,6 @@ = parent:String children:("." (Integer / "address"))* { | ||
} | ||
String "string" | ||
= _ "$"?[a-zA-Z0-9_]+ { return text(); } | ||
ConstString | ||
= _ "\\""str:([a-zA-Z0-9_.,\\-{}$]*)"\\"" { return str.join(''); } | ||
_ "whitespace" | ||
@@ -126,0 +146,0 @@ = [ \\t\\n\\r]* |
@@ -1,4 +0,4 @@ | ||
import { PropertyDef } from './PropertyDef'; | ||
import { Program } from './PropertyDef'; | ||
export declare class Parser { | ||
parse(src: string): PropertyDef[]; | ||
parse(src: string): Program; | ||
} |
@@ -21,5 +21,6 @@ "use strict"; | ||
const testOutput = loadTest('operators/and'); | ||
const ast = parser.parse(testOutput); | ||
const ast = parser.parse(testOutput).declarations; | ||
expect(ast).toStrictEqual([ | ||
{ | ||
annotations: [], | ||
name: 'andTest', | ||
@@ -40,5 +41,6 @@ inputDefs: ['a', 'b'], | ||
const testOutput = loadTest('operators/or'); | ||
const ast = parser.parse(testOutput); | ||
const ast = parser.parse(testOutput).declarations; | ||
expect(ast).toStrictEqual([ | ||
{ | ||
annotations: [], | ||
name: 'orTest', | ||
@@ -59,5 +61,6 @@ inputDefs: ['a', 'b'], | ||
const testOutput = loadTest('operators/not'); | ||
const ast = parser.parse(testOutput); | ||
const ast = parser.parse(testOutput).declarations; | ||
expect(ast).toStrictEqual([ | ||
{ | ||
annotations: [], | ||
name: 'notTest', | ||
@@ -77,5 +80,6 @@ inputDefs: ['a'], | ||
const testOutput = loadTest('operators/forall'); | ||
const ast = parser.parse(testOutput); | ||
const ast = parser.parse(testOutput).declarations; | ||
expect(ast).toStrictEqual([ | ||
{ | ||
annotations: [], | ||
name: 'forallTest', | ||
@@ -97,5 +101,6 @@ inputDefs: ['a'], | ||
const testOutput = loadTest('operators/there'); | ||
const ast = parser.parse(testOutput); | ||
const ast = parser.parse(testOutput).declarations; | ||
expect(ast).toStrictEqual([ | ||
{ | ||
annotations: [], | ||
name: 'thereTest', | ||
@@ -115,2 +120,18 @@ inputDefs: [], | ||
}); | ||
test('there without child', () => { | ||
const testOutput = `def thereTest() := A().any()`; | ||
const ast = parser.parse(testOutput).declarations; | ||
expect(ast).toStrictEqual([ | ||
{ | ||
annotations: [], | ||
name: 'thereTest', | ||
inputDefs: [], | ||
body: { | ||
type: 'PropertyNode', | ||
predicate: 'ThereExistsSuchThat', | ||
inputs: [{ type: 'PropertyNode', predicate: 'A', inputs: [] }] | ||
} | ||
} | ||
]); | ||
}); | ||
}); | ||
@@ -120,5 +141,6 @@ describe('bind', () => { | ||
const testOutput = loadTest('bind/bindand'); | ||
const ast = parser.parse(testOutput); | ||
const ast = parser.parse(testOutput).declarations; | ||
expect(ast).toStrictEqual([ | ||
{ | ||
annotations: [], | ||
name: 'bindAndTest', | ||
@@ -139,5 +161,6 @@ inputDefs: ['a'], | ||
const testOutput = loadTest('bind/bindval'); | ||
const ast = parser.parse(testOutput); | ||
const ast = parser.parse(testOutput).declarations; | ||
expect(ast).toStrictEqual([ | ||
{ | ||
annotations: [], | ||
name: 'bindValTest', | ||
@@ -159,5 +182,6 @@ inputDefs: ['a'], | ||
const testOutput = loadTest('bind/bind2'); | ||
const ast = parser.parse(testOutput); | ||
const ast = parser.parse(testOutput).declarations; | ||
expect(ast).toStrictEqual([ | ||
{ | ||
annotations: [], | ||
name: 'bind2Test', | ||
@@ -178,5 +202,6 @@ inputDefs: ['a'], | ||
const testOutput = loadTest('bind/bindaddr'); | ||
const ast = parser.parse(testOutput); | ||
const ast = parser.parse(testOutput).declarations; | ||
expect(ast).toStrictEqual([ | ||
{ | ||
annotations: [], | ||
name: 'bindAddrTest', | ||
@@ -203,5 +228,6 @@ inputDefs: ['a'], | ||
const testOutput = loadTest('variable/eval1'); | ||
const ast = parser.parse(testOutput); | ||
const ast = parser.parse(testOutput).declarations; | ||
expect(ast).toStrictEqual([ | ||
{ | ||
annotations: [], | ||
name: 'evalTest', | ||
@@ -222,5 +248,6 @@ inputDefs: ['a', 'b'], | ||
const testOutput = loadTest('variable/forval'); | ||
const ast = parser.parse(testOutput); | ||
const ast = parser.parse(testOutput).declarations; | ||
expect(ast).toStrictEqual([ | ||
{ | ||
annotations: [], | ||
name: 'forValTest', | ||
@@ -242,5 +269,6 @@ inputDefs: ['a'], | ||
const testOutput = loadTest('variable/thereval'); | ||
const ast = parser.parse(testOutput); | ||
const ast = parser.parse(testOutput).declarations; | ||
expect(ast).toStrictEqual([ | ||
{ | ||
annotations: [], | ||
name: 'thereValTest', | ||
@@ -262,5 +290,6 @@ inputDefs: [], | ||
const testOutput = loadTest('variable/thereval2'); | ||
const ast = parser.parse(testOutput); | ||
const ast = parser.parse(testOutput).declarations; | ||
expect(ast).toStrictEqual([ | ||
{ | ||
annotations: [], | ||
name: 'thereValTest', | ||
@@ -281,4 +310,68 @@ inputDefs: ['a'], | ||
}); | ||
describe('import', () => { | ||
test('import', () => { | ||
const testOutput = ` | ||
from aaa import bbb | ||
def Foo(a, b) := Bool(a) and Bool(b) | ||
`; | ||
const ast = parser.parse(testOutput); | ||
expect(ast).toStrictEqual({ | ||
imports: [ | ||
{ | ||
path: 'aaa', | ||
module: 'bbb' | ||
} | ||
], | ||
declarations: [ | ||
{ | ||
annotations: [], | ||
name: 'Foo', | ||
inputDefs: ['a', 'b'], | ||
body: { | ||
type: 'PropertyNode', | ||
predicate: 'And', | ||
inputs: [ | ||
{ type: 'PropertyNode', predicate: 'Bool', inputs: ['a'] }, | ||
{ type: 'PropertyNode', predicate: 'Bool', inputs: ['b'] } | ||
] | ||
} | ||
} | ||
] | ||
}); | ||
}); | ||
}); | ||
describe('annotation', () => { | ||
test('annotation', () => { | ||
const testOutput = ` | ||
@quantifier("bucket\${b},type,\${a}") | ||
def Foo(a, b) := Bool(a) and Bool(b) | ||
`; | ||
const ast = parser.parse(testOutput); | ||
expect(ast).toStrictEqual({ | ||
imports: [], | ||
declarations: [ | ||
{ | ||
annotations: [ | ||
{ | ||
type: 'Annotation', | ||
body: { name: 'quantifier', args: ['bucket${b},type,${a}'] } | ||
} | ||
], | ||
name: 'Foo', | ||
inputDefs: ['a', 'b'], | ||
body: { | ||
type: 'PropertyNode', | ||
predicate: 'And', | ||
inputs: [ | ||
{ type: 'PropertyNode', predicate: 'Bool', inputs: ['a'] }, | ||
{ type: 'PropertyNode', predicate: 'Bool', inputs: ['b'] } | ||
] | ||
} | ||
} | ||
] | ||
}); | ||
}); | ||
}); | ||
}); | ||
}); | ||
//# sourceMappingURL=Parser.test.js.map |
@@ -0,1 +1,16 @@ | ||
export interface Program { | ||
imports: Import[]; | ||
declarations: PropertyDef[]; | ||
} | ||
export interface Import { | ||
path: string; | ||
module: string; | ||
} | ||
export interface Annotation { | ||
type: 'Annotation'; | ||
body: { | ||
name: string; | ||
args: string[]; | ||
}; | ||
} | ||
/** | ||
@@ -5,2 +20,3 @@ * Parsed Property definition | ||
export interface PropertyDef { | ||
annotations: Annotation[]; | ||
name: string; | ||
@@ -7,0 +23,0 @@ inputDefs: string[]; |
{ | ||
"name": "@cryptoeconomicslab/ovm-parser", | ||
"version": "0.2.3", | ||
"version": "0.2.5", | ||
"description": "OVM parser", | ||
@@ -54,3 +54,3 @@ "author": { | ||
}, | ||
"gitHead": "16a79feb8d5b9e1adf22d5e5efc270aab3070249" | ||
"gitHead": "a6fe87e695170363ae93fa6b65261aee7a6b6bca" | ||
} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
34464
568