However, there is one way in which Bento objects are unique. In Bento, all objects
are considered data; they may contain logic, but this logic is not directly
visible to a user of the object. All the user sees is the data generated by
the logic.
Because Bento objects are data, not logic, Bento objects do not have callable functions
in the conventional sense. The only methods in Bento are constructors.
This is a feature, not a flaw. Bento is capable of performing any computation
or implementing any algorithm, but the logic must be properly encapsulated. This up
front architectural cost is minor compared to the increased reliability and ease of
maintenance which is achieved.
A Bento site is defined in one or more Bento files, which generally have a ".bento"
extension. The Bento processor reads these files and builds an internal representation
of their contents. This representation is then used to generate pages.
Comments may appear anywhere except inside static blocks or quoted strings. Comments may be
nested.
Contained in the site and core definitions are object definitions, which may in turn
contain more definitions. Object definitions may also contain constructions, which
are the Bento statements that actually build the object.
Static blocks may have embedded dynamic blocks and vice versa. Here is the same
dynamic block as above, but with three static blocks embedded in it:
The following example consists of a site definition containing a typed,
unparamaterized object definition, which itself contains an untyped array
definition.
The following example consists of an object definition containing a number
of different kinds of constructions, along with an object definition.
| Name := IDENTIFIER | There is one namespace in Bento, but the meaning of a name depends on its scope, and there are many scopes. |
| Value := Block | ValueExpr | ArrayBody | TableBody | A value is something which can be evaluated: an expression, a block or a collection. |
| Block := ("[/]" | "[?]" | "[&]" | DataBlock | BentoBlock) [ CatchBlock ] | A block is a container, possibly empty, of code or data. |
| Literal := NullLiteral | BooleanLiteral | NumericLiteral | TextLiteral | |
| NullLiteral := "null" | |
| BooleanLiteral := "true" | "false" | |
| NumericLiteral := DECIMAL_INTEGER | HEX_INTEGER | FLOATING_POINT_NUMBER | |
| TextLiteral := CHARACTER | STRING | |
| DataBlock := StaticBlock | LiteralBlock | |
| StaticBlock := ("[|" | "[/") [STATIC_TEXT] (Block [STATIC_TEXT])* ("|]" | "/]") | |
| LiteralBlock := \"[``\" [LITERAL_TEXT] \"``]\" | |
| BentoBlock := "[=" (Directive | Definition | Construction)* "=]" | |
| CatchBlock := "catch" [DefinitionNameExpr] Block | |
| DefinitionNameExpr := "(" DefinitionNameExpr ")" | DefinitionName | |
| Directive := "keep" Name ("," Name)* | "discard" Name ("," Name)* | |
| Comment := DocComment | NondocComment | |
| DocComment := "/*" [COMMENT_TEXT] (Comment [COMMENT_TEXT])* "*/" | |
| NondocComment := "/--" [COMMENT_TEXT] (Comment [COMMENT_TEXT])* "--/" | |
| Type := SimpleType | CollectionType | |
| SimpleType := TypeName [ArgumentList] | PrimitiveType [SingleArgument] | |
| CollectionType := SimpleType (IndefiniteDim)+ | |
| TypeName := Name ("." Name)* | |
| ArgumentList := "(" [Argument ("," Argument)*] ")" | |
| Argument := DefinitionRef | Value | |
| DefinitionRef := ["super" | "this" | "owner" "."] TypeName | |
| PrimitiveType := "boolean" | "byte" | "char" | "double" | "float" | "int" | "long" | "string" | |
| SingleArgument := "(" Argument ")" | |
| ValueExpr := LogicalOrExpr ["?" ValueExpr ":" ValueExpr] | |
| LogicalOrExpr := LogicalAndExpr ("||" LogicalAndExpr)* | |
| LogicalAndExpr := OrExpr ("&&" OrExpr)* | |
| OrExpr := XorExpr ("|" XorExpr)* | |
| XorExpr := AndExpr ("^" AndExpr)* | |
| AndExpr := EqualityExpr ("&" EqualityExpr)* | |
| EqualityExpr := RelationalExpr (("==" | "!=") RelationalExpr)* | |
| RelationalExpr := IsaExpr | ShiftExpr (("<" | ">" | "<=" | ">=") ShiftExpr)* | |
| IsaExpr := PrimaryExpr ("isa" | "?=") Type | |
| ShiftExpr := AdditiveExpr (("<<" | ">>" | ">>>") AdditiveExpr)* | |
| AdditiveExpr := MultiplicativeExpr (("+" | "-") MultiplicativeExpr)* | |
| MultiplicativeExpr := UnaryExpr (("*" | "/" | "%") UnaryExpr)* | |
| UnaryExpr := ("+" | "-" | "~" | "!" | "(" Type ")") PrimaryExpr | |
| PrimaryExpr := "(" ValueExpr() ")" | Literal | ComplexName | |
| Definition := [Modifier] (ComplexDefinition | ElementDefinition | ArrayDefinition | TableDefinition) | |
| Modifier := AccessModifier [DurabilityModifier] | DurabilityModifier [AccessModifier] | |
| AccessModifier := "local" | "public" | |
| DurabilityModifier := "static" | "dynamic" | |
| ComplexDefinition := [SimpleTypeList] DefinitionName Block | |
| SimpleTypeList := SimpleType ("," SimpleType)* | |
| DefinitionName := Name [ParameterList ("," ParameterList)*] | |
| ParameterList := "(" [Parameter ("," Parameter)*] ")" | |
| Parameter := FormalParameter | "*" | |
| FormalParameter := [TypeName (IndefiniteDim)*] Name (IndefiniteDim)* | |
| ElementDefinition := ElementName "=" Value) [";"] | |
| ElementName := DefinitionName ("[" ("+" | ValueExpr) "]" | "{" ValueExpr "}")* | |
| Construction := TypeConstruction | LogicConstruction | Redirection | AnonConstruction | NamedConstruction | |
| Instance := "(" Instance ")" | ComplexName | |
| TypeConstruction := ("sub" | "super") ";" | |
| Redirection := "redirect" Instance [";"] | |
| AnonConstruction := "(" ValueExpr() ")" ";" | StringLiteral ";" | AnonDefinition rule(";" ] | |
| AnonDefinition := [ ParameterList ("," ParameterList)* ] Block | |
| NamedConstruction := ComplexName ["." NameSuffix] ";" | |
| ComplexName := [NamePrefix "."] (NamePart ".")* NamePart | |
| NamePrefix := "super" | "this" | "owner" | |
| NamePart := Name [ArgumentList] ("[" ValueExpr "]" | "{" ValueExpr "}")* | |
| NameSuffix := "type" | "count" | |
| LogicConstruction := Conditional | Loop | |
| Conditional := ("if" ValueExpr | "with" WithPredicate) Block ("else" ("if" ValueExpr | "with" WithPredicate) Block)* ["else" Block] | |
| WithPredicate := "(" WithPredicate ")" | Name | |
| Loop := "for" Iterator (("and" | "or") Iterator)* Block | |
| Iterator := FormalParamter ("in" Instance | "from" ValueExpr ["to" ValueExpr] ["by" ValueExpr]) ["where" ValueExpr] ["until" ValueExpr] | |
| CollectionDefinition := ArrayDefinition | TableDefinition | |
| Dim := "[" [ValueExpr] "]" | "{" [ValueExpr] "}" | |
| IndefiniteDim := "[" "]" | "{" "}" | |
| ArrayDefinition := ([Type] ArrayName | ArrayType ElementName) "=" ArrayConstruction | |
| ArrayName := DefinitionName ArrayDim (Dim)* | |
| ArrayType := SimpleType ArrayDim (IndefiniteDim)* | |
| ArrayDim := "[" [ValueExpr] "]" | |
| TableDefinition := ([Type] TableName | TableType ElementName) "=" TableConstruction | |
| TableName := DefinitionName TableDim (Dim)* | |
| TableType := SimpleType TableDim (IndefiniteDim)* | |
| TableDim := "{" [ValueExpr] "}" | |
| ArrayConstruction := (Instance | ArrayBody | "[&]") [";"] | |
| TableConstruction := (Instance | TableBody | "[&]") [";"] | |
| ArrayBody := ( "[" "]" | "[" "..." ("," ArrayElement)* "]" | "[" ArrayElement ("," ArrayElement)* ["," "..." ("," ArrayElement)*] "]") | |
| ArrayElement := DefinitionReference | Value | ArrayComprehension | |
| TableBody := ( "[" "]" | "[" [DefaultTableElement ","] TableElement ("," TableElement)* "]") | |
| DefaultTableElement := "{" (DefinitionReference | Value) "}" | |
| TableElement := "{" ValueExpr "," (DefinitionReference | Value) "}" | TableComprehension | |
| ArrayComprehension := ArrayConditional | ArrayFor | ArrayBlock | |
| ArrayConditional := ("if" ValueExpr | "with" WithPredicate) ArrayBlock ("else" ("if" ValueExpr | "with" WithPredicate) ArrayBlock)* ["else" ArrayBlock] | |
| ArrayFor := "for" Iterator (("and" | "or") Iterator())* ArrayBlock | |
| ArrayBlock := "[[" [ ArrayElement ("," ArrayElement)* ] "]]" [ArrayCatchBlock] | |
| ArrayCatchBlock := "catch" [DefinitionNameExpr] ArrayBlock | |
| TableComprehension := TableConditional | TableFor | TableBlock | |
| TableConditional := ("if" ValueExpr | "with" WithPredicate) TableBlock ("else" ("if" ValueExpr | "with" WithPredicate) TableBlock)* ["else" TableBlock] | |
| TableFor := "for" Iterator (("and" | "or") Iterator())* TableBlock | |
| TableBlock := "[[" [ TableElement ("," TableElement)* ] "]]" [TableCatchBlock] | |
| TableCatchBlock := "catch" [InstanceExpr] TableBlock | |
| BentoFile := (CoreDefinition | SiteDefinition)+ | |
| CoreDefinition := "core" SiteBlock | |
| SiteDefinition := "site" Name SiteBlock | |
| SiteBlock := "[=" (SiteLevelDirective)* (SiteLevelDefinition)* "=]" | |
| SiteLevelDirective := "join" NameRange | "extern" Name NameRange | |
| NameRange := Name ("." (Name | "*"))* ["." "**"] | |
| SiteLevelDefinition := SiteDefinition | Definition | |
| STATIC_TEXT := ~<"[|" | "[/" | "[``" | "[=" | "|]" | "/]">* | |
| LITERAL_TEXT := ~<\"``]\">* | |
| COMMENT_TEXT := ~<"/*" | "/--">* | |
| DECIMAL_INTEGER := <"1"-"9"> * <"l" | "L">? | |
| HEX_INTEGER := <"0x" | "0X" | "#"> + <"l" | "L">? | |
| FLOATING_POINT_NUMBER := + <"."> * ? ? | <"."> + ? ? | + ? | + ? | |
| EXPONENT := <"e" | "E"> <"+" | "-">? + | |
| FP_MARK := <"f" | "F" | "d" | "D"> | |
| CHARACTER := <"'"> (~<"'" | "\" | "\n" | "\r"> | ) <"'"> | |
| STRING := <"""> (~<""", [``\", [``\n", [``\r"> | )* <"""> | |
| ESCAPE_SEQUENCE := <"\"> (<"n","t","b","r","f","\","'","""> | <"0"-"7"> <"0"-"7">? | <"0"-"3"> <"0"-"7"> <"0"-"7">) | |
| IDENTIFIER := * | |
| LETTER := <"A"-"Z", [``a"-"z"> | |
| DIGIT := <"0"-"9"> | |
| SPACE := <" " | "\t" | "\n" | "\r" | "\f">* | |