Differences
This shows you the differences between two versions of the page.
| Both sides previous revision Previous revision Next revision | Previous revision | ||
|
ego_script [2026/07/17 18:42] hermann |
ego_script [2026/07/22 20:26] (current) hermann |
||
|---|---|---|---|
| Line 3: | Line 3: | ||
| ====== Introduction ====== | ====== Introduction ====== | ||
| - | EGO Script is a simple, text-based language for creating and editing Dinamica EGO models. A model written in this format is stored in a file with the ''.ego'' extension. An ''.ego'' file is just another way of describing a model — it is equivalent to the XML form Dinamica EGO uses internally. Because the two are interchangeable, you can write a model as an EGO script, open it in the graphical interface, edit it there, and save it again, moving freely between the textual and visual representations. | + | EGO Script is a simple, text-based language for creating and editing Dinamica EGO models. A model written in this format is stored in a file with the ''.ego'' extension. An ''.ego'' file is just another way of describing a model — it is equivalent to the XML form Dinamica EGO uses internally. Because the two are interchangeable, you can write a model as an EGO script, open it in the graphical interface, edit it there, and save it again, moving freely between the textual and visual representations. See [[basic_data_flow|Basic Data Flow]] for the execution model shared by both representations; this tutorial covers the textual notation specifically. |
| > **Caution:** When you round-trip a model through the graphical interface, the interface can rewrite a model's layout and the format of its inputs and outputs according to the options currently in effect, so a script reopened and saved from the GUI may not come back byte-for-byte identical to what you wrote. This is normal, and the resulting model is equivalent. | > **Caution:** When you round-trip a model through the graphical interface, the interface can rewrite a model's layout and the format of its inputs and outputs according to the options currently in effect, so a script reopened and saved from the GUI may not come back byte-for-byte identical to what you wrote. This is normal, and the resulting model is equivalent. | ||
| Line 43: | Line 43: | ||
| A variable name must begin with an underscore or a letter, and may be followed by any combination of underscores, letters, and digits (''[_a-zA-Z][_a-zA-Z0-9]*''). Variable names are case-sensitive. | A variable name must begin with an underscore or a letter, and may be followed by any combination of underscores, letters, and digits (''[_a-zA-Z][_a-zA-Z0-9]*''). Variable names are case-sensitive. | ||
| - | Variables are the primary mechanism by which functors pass data to one another, and data dependencies are the main source of execution ordering. A variable must be bound by the functor that produces it before any functor that reads it can run — this is what creates a **dependency** between the two. Functors that do not share a variable, directly or through a chain of intermediate variables, have no dependency on each other and may execute in any order or at the same time. [[#container_functors|Container functors]], described in the Container functors section of the reference, impose a second ordering constraint on top of this. | + | Variables are the primary mechanism by which functors pass data to one another, and data dependencies are the main source of execution ordering. A variable must be bound by the functor that produces it before any functor that reads it can run — this is what creates a **dependency** between the two. Functors that do not share a variable, directly or through a chain of intermediate variables, have no dependency on each other and may execute in any order or at the same time. [[#container_functors|Container functors]], described in the Container functors section of the reference, impose a second ordering constraint on top of this. This is a property of the underlying functor graph, not of EGO Script specifically — see [[basic_data_flow|Basic Data Flow]]. |
| > **Note:** The position of a functor definition in the script file does not determine when it runs. Unless two functors are connected by a data dependency — directly or through a chain of variables — never assume anything about their relative execution order. The only exception is [[#container_functors|containers]], covered later in this section. | > **Note:** The position of a functor definition in the script file does not determine when it runs. Unless two functors are connected by a data dependency — directly or through a chain of variables — never assume anything about their relative execution order. The only exception is [[#container_functors|containers]], covered later in this section. | ||
| Line 104: | Line 104: | ||
| **Structured constants** — complex values enclosed in square brackets ''[ … ]'', specific to individual functors and can be multi-line: ''[ 2->1 0.05 ]'', ''[ "Key" "Value" ]''. | **Structured constants** — complex values enclosed in square brackets ''[ … ]'', specific to individual functors and can be multi-line: ''[ 2->1 0.05 ]'', ''[ "Key" "Value" ]''. | ||
| + | |||
| + | Lookup table literals support an additional shorthand: ''startKey startValue .. endKey endValue'' auto-generates every key from ''startKey'' to ''endKey'' (incrementing by one), with values linearly interpolated between ''startValue'' and ''endValue''. Range entries and plain ''key value'' entries can be mixed freely, and commas between entries are optional: | ||
| + | |||
| + | <code> | ||
| + | [ "Key" "Value", 1 1 .. 4 1, 5 -8, 6 1 .. 9 1 ] | ||
| + | </code> | ||
| + | |||
| + | Since the start and end values in each range above are equal, interpolating between them keeps the value constant — keys 1–4 and 6–9 all map to ''1'', and key 5 maps to ''-8''. When a script is saved from the GUI, ranges like this are automatically collapsed back into ''..'' notation where possible. See [[lookup_table_type|Lookup Table Type]] for the full syntax, including optional key/value column names, and [[table_type|Table Type]] for the syntax rules that apply to tables in general. | ||
| + | |||
| + | A general table follows the same bracket syntax but allows any number of columns, mixing Real and String data, with types inferred from each column's own values unless overridden with a ''#type'' suffix: | ||
| + | |||
| + | <code> | ||
| + | [ | ||
| + | "PatchId*#string", "Area", "Category", | ||
| + | 007, 12.4, "forest", | ||
| + | 013, 8.7, "pasture" | ||
| + | ] | ||
| + | </code> | ||
| + | |||
| + | Without the ''#string'' override, ''PatchId'''s unquoted values would be inferred as Real numbers — ''007'' would collapse to the number ''7'', losing its leading zero. The explicit type forces String interpretation instead, preserving each value exactly as written. ''Area'' and ''Category'' are left to plain inference: Real from ''12.4''/''8.7'', String from the quoted ''"forest"''/''"pasture"''. | ||
| A call can mix all forms with variable references in a single argument list: | A call can mix all forms with variable references in a single argument list: | ||
| Line 241: | Line 261: | ||
| A **container functor** is a functor that holds other functors inside it. The contained functors execute within the container's scope. | A **container functor** is a functor that holds other functors inside it. The contained functors execute within the container's scope. | ||
| - | Containers are the second source of execution ordering in Dinamica EGO, alongside data dependencies. All functors inside a container execute as part of that container's execution. This means that if container B depends on container A — for example, B consumes a value produced by something inside A — then B will only start after A has fully completed. As a consequence, every functor inside B is guaranteed to run after every functor inside A, and the contents of the two containers will never execute simultaneously. | + | Containers are the second source of execution ordering in Dinamica EGO, alongside data dependencies. All functors inside a container execute as part of that container's execution. This means that if container B depends on container A — for example, B consumes a value produced by something inside A — then B will only start after A has fully completed. As a consequence, every functor inside B is guaranteed to run after every functor inside A, and the contents of the two containers will never execute simultaneously. See [[basic_data_flow|Basic Data Flow]] for how this fits into the broader, notation-independent execution model — including how containers also control whether and how many times their contents run. |
| Containers fall into a few families: | Containers fall into a few families: | ||
| Line 379: | Line 399: | ||
| }}; | }}; | ||
| </code> | </code> | ||
| + | |||
| + | > **Note:** A mux's feedback input is the one exception to the dependency rule in [[#functors_variables_and_binding|Functors, variables, and binding]] — the mux does not wait for the functor that produces its feedback value to run before it runs; it emits the value that functor produced on the previous iteration instead. This is also why, in the example above, ''nextCount'' is passed into ''MuxValue'' on a line above the line that assigns ''nextCount'': the mux and the calculator each depend on the other's output, so no matter which one is written first in the script, the other's variable is necessarily used before it is assigned. | ||
| A **junction** selects between two dataflows. It reads its first input; if that input carries data, the junction passes it through. If the first input is empty, it passes the second input through instead. If both are empty, the junction reports an error. Junctions are typed, with one per data kind — [[Map Junction]], [[Categorical Map Junction]], [[Table Junction]], [[Lookup Table Junction]], [[Value Junction]], [[String Junction]], and so on: | A **junction** selects between two dataflows. It reads its first input; if that input carries data, the junction passes it through. If the first input is empty, it passes the second input through instead. If both are empty, the junction reports an error. Junctions are typed, with one per data kind — [[Map Junction]], [[Categorical Map Junction]], [[Table Junction]], [[Lookup Table Junction]], [[Value Junction]], [[String Junction]], and so on: | ||
| Line 503: | Line 525: | ||
| Converting abbreviated syntax to verbose is always lossless. Converting verbose to abbreviated is only possible when all hooks are free of comments, properties, and identifiers that do not appear in the expression. | Converting abbreviated syntax to verbose is always lossless. Converting verbose to abbreviated is only possible when all hooks are free of comments, properties, and identifiers that do not appear in the expression. | ||
| + | |||
| + | > **Note:** This distinction applies only to saved or generated script text. The graphical interface always displays and edits a calculator functor's expression in the verbose ''i1''/''t1''/''v1'' form, with each hook represented as its own functor node, regardless of whether the //Use abbreviated syntax// option is enabled or which form the underlying file uses. The ''#name''/''%name''/''$name'' abbreviated form exists only in script text; the graphical interface has no corresponding abbreviated representation. | ||
| A common situation where this matters: if you connect a map or lookup table purely to define the output format — not because it is referenced in the expression — connecting it via a ''NumberMap'' or ''NumberTable'' hook will block abbreviated syntax, since the hook defines an identifier absent from the expression. Use the dedicated port instead: the ''Result Format'' input port for map calculators, or the ''Base Lookup Table'' input port for lookup table calculators. These connections do not create hooks and do not affect the availability of abbreviated syntax. | A common situation where this matters: if you connect a map or lookup table purely to define the output format — not because it is referenced in the expression — connecting it via a ''NumberMap'' or ''NumberTable'' hook will block abbreviated syntax, since the hook defines an identifier absent from the expression. Use the dedicated port instead: the ''Result Format'' input port for map calculators, or the ''Base Lookup Table'' input port for lookup table calculators. These connections do not create hooks and do not affect the availability of abbreviated syntax. | ||
| Line 671: | Line 695: | ||
| | ''extendedcomment'' | ''dff.functor.extendedcomment'' | The functor's extended comment — the text after ''==='' in a ''<nowiki>//</nowiki>'' comment (see [[#comments|Comments]]). | | | ''extendedcomment'' | ''dff.functor.extendedcomment'' | The functor's extended comment — the text after ''==='' in a ''<nowiki>//</nowiki>'' comment (see [[#comments|Comments]]). | | ||
| | ''collapsed'' | ''dff.container.collapsed'' | Indicates that a container is drawn closed (its contents hidden) in the graphical interface. Applies to containers only. Values: ''yes''/''no'' or ''true''/''false''. | | | ''collapsed'' | ''dff.container.collapsed'' | Indicates that a container is drawn closed (its contents hidden) in the graphical interface. Applies to containers only. Values: ''yes''/''no'' or ''true''/''false''. | | ||
| + | | ''ignoredIssues'' | ''dff.functor.ignoredissues'' | Suppresses a specific category of GUI warning for the functor — observed values include ''Experimental'' (the functor is experimental) and ''ResultIgnored'' (an output is intentionally left unused). | | ||
| > **Note:** A few per-functor properties exist only while a model is open in the editor and are never written to the saved model: ''dff.functor.text'', ''dff.functor.file'', ''dff.functor.line'', and ''dff.functor.column''. | > **Note:** A few per-functor properties exist only while a model is open in the editor and are never written to the saved model: ''dff.functor.text'', ''dff.functor.file'', ''dff.functor.line'', and ''dff.functor.column''. | ||
| Line 726: | Line 751: | ||
| | ''map2Region'' | ''Map 2 Region'' | | | ''map2Region'' | ''Map 2 Region'' | | ||
| | ''saddleHeight2'' | ''Saddle Height 2'' | | | ''saddleHeight2'' | ''Saddle Height 2'' | | ||
| + | |||
| + | One case is excluded from this reconstruction: a variable name that is just the functor's own name, lowercased at the front, with a trailing number — for example ''lookupTable0'' for a ''LookupTable'' functor. This pattern is recognized as an **auto-generated name**: one the GUI assigned on its own because no alias was ever set, rather than a name a person chose. Such names are not reconstructed into an alias like ''Lookup Table 0''; the functor is simply shown with no alias. | ||
| ==== Model-level metadata ==== | ==== Model-level metadata ==== | ||
| Line 974: | Line 1001: | ||
| hectaresColumn := GetTableColumn areaTable 3; | hectaresColumn := GetTableColumn areaTable 3; | ||
| </code> | </code> | ||
| - | |||
| - | |||