logica
Version:
a compile-to-javascript predicate logic language
122 lines (72 loc) • 4.29 kB
Markdown
# logica
a compile-to-javascript predicate logic language
note: this is a preview public release, so documentation is a bit sparse right now.
logica is a language for expressing [Boolean algebra](http://en.wikipedia.org/wiki/Boolean_algebra). It's clean syntax makes it easy for non-programmers and domain experts to express complex logic and conditional knowledge.
* flexible syntax
* interpreted or compile-to-javascript
* all operators support multiple arguments (except `not`)
* extensible with custom predicate operators
## basic usage
in logica, you create predicates (functions which result in a `true` or `false` value). The simplest predicate is a literal boolean value. That is, the following is valid logica:
true
This, clearly, will always evaluate to true. Of course, you probably want more complex things:
(OR
(Today = "wednesday")
(Today = "mittwoch")
)
Whitespace doesn't matter, but it can improve usability. Optionally, commas can be used to separate the various pieces. We could also write:
(OR,(Today="wednesday"),(=,Today,"mittwoch"))
Here, we're using a symbolic variable, `Today`, and comparing it to the literal values `wednesday` and `mittwoch`.
In JavaScript, you might write:
Today === "wednesday" || Today === "mittwoch"
Notice the parentheses? You can nest predicates as deeply as you'd like.
Note that since this predicate references `Today`, we can't evaluate it without a value for `Today`. It might help to think about it like this: in logica, you're writing a function. Each symbolic variable you use requires a corresponding argument. When using logica in JavaScript, these are supplied as properties on a `state` object which is passed in.
Putting it all together,
var logica = require('logica')
var source = '(OR (Today = "wednesday"), (Today = "mittwoch"))'
logica.exec(source, {Today: 'mittwoch'})
// => true
logica.exec(source, {Today: 'wednesday'})
// => true
logica.exec(source, {Today: 'tuesday'})
// => false
Now that you've got the basics, check out the `/examples/` folder for more.
A slightly more elaborate (and contrived, but valid) predicate might be:
# a logica program
(AND
(foo = 'baz')
faa
(NOT (NOT true))
(pizzas >= 23)
('cheese' IN toppings)
(and (foo = bar))
)
## using the compiler
logica can be compiled to JavaScript sourcecode so that the overhead of parsing only has to occur once. For example, a server can pre-compile logica predicates for use on a client application.
in node, simply:
var compile = require('logica')
var jsCode = compile(sourceString, options);
## using a compiled function
The compiler generates JavaScript sourcecode as a string. This intermediate form expects certain functions to exist in the runtime environment implementing logica operators.
The easiest way to consume this source is using the hydrate function:
var hydrate = require('logica/hydrate')
var logicaFn hydrate(compiledLogicaSource)
var state = { foo: true, bar: false }
var result = logicaFn(state)
Hydrate is a standalone module with no dependencies. You can use it, for example, to execute functions clientside that were precompiled on the server.
## compile options
You can supply and `opts` object as the optional second argument of `compile`.
- `prettyPrint`: boolean (default false). If true, will generate code with line breaks and indentation
## examples
See the `/examples` folder. Files ending in `.logica` are plain logica source files.
## running the unit tests
$ make test
## hacking on the parser
logica's parser is implemented in [jison](http://zaach.github.com/jison/). The lexer and parser definitions are implemented in the file `logica.jison`, which generates `parser.js`. This file will get overwritten - do not make modifications to this file. Instead, modifications can be made in `logica.jison` itself or in `postParser.js`, which is just JavaScript.
To generate `parser.js`:
$ make
## contributors
Jason Denizac - jden - <jason.org>
## license
MIT (c) 2013 Agile Diagnosis, Inc.
See LICENSE.md