Rule Syntax Documentation

Is there some doc on the rule syntax?
How are the rules implemented internally? Is it an ANTLR parser? where could I get a hold of the grammar files?

1 Like

The rules are a Domain Specific Language based on the Xbase language and it bares the most resemblance to the Xtend language with some missing features (e.g. Xtend supports classes and arrays but the DSL does not). Your best bet is to look at the Xtend documentation here for the syntax of expressions (e.g. for loops, case statements, etc) and the Rule’s wiki page here for how rules files themselves are structured.

As for how it is implemented internally I can’t say. But if there are grammar files they will all be in the GitHub repo.

1 Like

I have still the same questions like @earlenceferns. For example, where can i find the methods of the org.openhab.core.* or org.openhab.model.script.* libs and how does i know witch includes i can use? I mostly program microcontrollers in C-language and the Xtend-docu is a little confusing to me. For example, witch datatypes are supported, is a switch case possible with a number variable where are the [1…2] forEach [| ] loop are documented, how can i handle negative values and so on…

If you are on OH 2.x then all of those classes are now moved to Eclipse SmartHome.

All of these are now included by default. In addition, java.lang.*, and org.joda.time.* are included by default. The only things you need to import are external (i.e. non-openHAB, non-Eclipse SmartHome) libraries. For example, you need to import java.util.Map but not SwitchItem or Timer.

The easiest way to find out what methods and data are available on individual classes is to use Designer, type out the name of a Object followed by a . (basically, start typing the code as you would) and press <ctrl><space>. This will bring up a list of all the valid ways to complete the part of the line you have started typing. You can arrow through the list, hit <enter> and Designer will complete the line with that selection.

In addition, the JavaDoc for all the Eclipse SmartHome classes is located here.

This is a very different language from what you are used to. Unlike C, The Rules DSL is not strongly typed. Unfortunately, this can cause some problems, particularly in those situations where the language is not able to infer the correct type based on usage.

But the short answer is all of the primatives supported by Java, all of the Classes built into Java, all of the Classes built into Eclipse SmartHome (I think, it might just be a subset), all of the Classes built into Xtext, and all of the Classes built into Joda are supported DataTypes. However, in practice you will almost always only ever deal with:

  • Joda DateTimes (e.g. now)
  • Items
  • States
  • Strings
  • very occasionally primatives

Some common gotchas include:

  • when doing math, unless the data type of each part of the calculation and the datatype of the result is specified, the result will be a java.lang.BigDecimal
  • primatives are usually automatically converted to their Object equvilents automatically
  • DecimalType (the data type for the state of a Number Item) is also of type Number and some method calls will throw an ambiguous call error because there is a version of the method that takes a DecimalType and another that takes a Number and the Rules DSL can’t figure out which you meant.

As a general rule, I avoid specifying the type unless I have to as the Rules DSL, like most not strongly typed languages, does a pretty good job of figuring out what you need. I find fewer errors occur when we let the language handle casting between the various data types.

For language constructs see the Expressions section of the Xtend documentation. Both the Rules DSL and Xtend are based on the same underlying language. There are some differences though to be aware of.

  • the Rules DSL does not support arrays
  • I don’t think the Rules DSL supports infix or postfix operators
  • you do have to import org.eclipse.xtext.xbase.lib.Functions to create named lambdas
  • the Rules DSL does not support creating your own classes so no Anonymous classses
  • I don’t think all the ways described to do for loops are supported but I without arrays and Groups I’ve yet to encounter a situation where I need them, the while loop works the same though
  • I don’t know if synchronized or templates work, never tried them

The switch case is unlike switch cases that you may be used to. From the Xtend docs:

The use of switch is not limited to certain values but can be used for any object reference. Object.equals(Object) is used to compare the value in the case with the one you are switching over.

Allowing for case statements beyond simple equals like more traditional switch statements. The example they give:

switch myString {
  case myString.length > 5 : "a long string."
  case 'some' : "It's some string."
  default : "It's another short string."
}

And example from my rules:

  switch now {
        case now.isAfter(morning_start)   && now.isBefore(day_start):       curr = "MORNING"
        case now.isAfter(day_start)       && now.isBefore(afternoon_start): curr = "DAY"
        case now.isAfter(afternoon_start) && now.isBefore(evening_start):   curr = "AFTERNOON"
        case now.isAfter(evening_start)   && now.isBefore(night_start):     curr = "EVENING"
        case now.isAfter(night_start):                                      curr = "NIGHT"
        case now.isAfter(bed_start)       && now.isBefore(morning_start):   curr = "BED"
  }

Also note that the switch does not support automation fall through like traditional switch statements. To get that behavior you you separate all the cases that you want to execute the same code for with a comma.

    switch str {
        case "One",
        case "Two": // some code
        case "Three": //some code
        default: // some code
    }

I don’t know what the notation [1…2] means in this context so can’t say whether that would be supported. But I’ve certain you can get the result you are after.

The documentation for forEach and the other methods that exists on collections are not as well documented. I cobbled together a bunch from examples and StackOverflow postings and such and documented how to use these methods, in the context of members of a Group but they also work with Lists you may create yourself. You can find that here:

In general, whenever you see square brackets what you are seeing is a lambda. A lambda is basically a function that you can pass around and treat like it where an Object (because it is an Object). The arguments passed to the lambda occur before the | and the code to execute occurs after.