Goldie Homepage

Documentation (v0.3)
Goldie -> Documentation (v0.3) -> API Overview -> Static And Dynamic Styles

Static And Dynamic Styles

Goldie supports two different styles of interfaces: a static-style and a dynamic-style. Both styles have pros and cons, and are suitable for different purposes. The differences are explained in the comparison chart and examples below.

Note that if you use StaticLang to embed a language directly into your program, you can switch back and forth between static and dynamic styles however you wish.

"Which Style Should I Use?"

You can use whichever you want, but the recommended rule of thumb is:

Use dynamic-style if you're doing something that isn't possible in static-style (like Parse or Parse Anything). Otherwise, use static-style.

Most apps will probably want to use static-style.

Comparison Chart

 

Static-style

Dynamic-style

Primary Benefits

Compile-time error checking Run-time flexibility

Ideal Uses

  • You're processing a very specific language.
  • You need high reliability.
  • You're creating a general language processing tool, like Parse or Parse Anything.
  • You need to support user-created languages.

Advance Knowledge of Language

Languages must be known ahead-of-time by the developer. Can use any user-supplied language, not just ones known by the developer at development-time. This enables programs like Parse and Parse Anything to be possible.

Note: Using a language not known at development-time naturally limits what you can do with the language, unless you have a way to programmatically infer semantic meaning from a grammar.

Loading a Language

Use StaticLang to embed the language directly into your program at compile-time. Load a .cgt file at run-time OR use StaticLang to embed the language directly into your program at compile-time.

Use of Invalid/Mistyped Symbol Names or Rules

Caught at compile-time. Not caught at compile-time or run-time. May cause subtle bugs.

Unhandled Tokens or Rules

Can be caught at run-time or compile-time, depending on your exact code.

(See Example: Checking a token's rule and retrieving a sub-token below.)
Not caught at compile-time or run-time. May cause subtle bugs.

Examples

The following examples use the calc language.

Example: Loading a Language

Static-style

// Run "staticlang calc.cgt /pack:myapp.mylangs" at command-line import goldie.all; import myapp.mylangs.calc.all; // Use 'language_calc'

Dynamic-style

Do the same as static-style, or:

import semitwist.util.io : getExecPath; import goldie.all; Goldie.langDir = getExecPath()~"{path to your cgt files}"; Language language_calc = Goldie.loadLanguage("calc"); // Use 'language_calc'

Or:

import goldie.all; Language language_calc = Goldie.loadCGT("calc.cgt"); // Use 'language_calc'

Example: Parsing a source

Static-style

auto rootToken = language_mylang.parseCode(src).parseTree;

The variable rootToken is of type Token_mylang!("<Add Exp>") (see Token_{languageName}!({symbol}) for details).

Dynamic-style

auto rootToken = language_mylang.parseCodeX(src).parseTreeX;

The variable rootToken is of type Token.

Example: Checking a token's symbol

Static-style

Just like checking for a rule (see below), but with Token_calc!("<Add Exp>") instead of Token_calc!("<Add Exp>", "<Add Exp>", "+", "<Mult Exp>")

Dynamic-style

bool isAddExp(Token tok) { return tok.name == "<AddExp>"; // Or to disambiguate (See the "Ambiguous Symbols" page): return tok.name == "<AddExp>" && tok.type == SymbolType.NonTerminal; }

Example: Checking a token's rule and retrieving a sub-token

Static-style

void useMultExpFromAddExp(T)(T tok) { // This represents the rule: <Add Exp> ::= <Add Exp> '+' <Mult Exp> static if(is( T == Token_calc!("<Add Exp>", "<Add Exp>", "+", "<Mult Exp>") )) { auto multExp = tok.sub!(2); } else // Doesn't match: Caught at compile-time }

Or:

void useMultExpFromAddExp(Token_calc!("<Add Exp>", "<Add Exp>", "+", "<Mult Exp>") tok) { auto multExp = tok.sub!(2); } // Omit this to catch "doesn't match" at compile-time: void useMultExpFromAddExp(Token tok) { // Doesn't match: Caught at **run-time** }

Or (not as highly recommended as the above):

void useMultExpFromAddExp(Token unknownTok) { if(auto tok = cast(Token_calc!("<Add Exp>", "<Add Exp>", "+", "<Mult Exp>"))unknownTok) { auto multExp = tok.sub!(2); } else // Doesn't match: Caught at **run-time** }

Dynamic-style

void useMultExpFromAddExp(Token tok) { // This represents the rule: <Add Exp> ::= <Add Exp> '+' <Mult Exp> if(tok.matches("<Add Exp>", "<Add Exp>", "+", "<Mult Exp>")) { auto multExp = tok.subX[2]; } }

More Examples

For a full-program example of static-style versus dynamic-style, see Calculator Static and Calculator Dynamic.