Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 88 additions & 0 deletions cheatsheet.md
Original file line number Diff line number Diff line change
Expand Up @@ -829,6 +829,94 @@ class My_Class {
};
```

## Strong Typedefs

Strong typedefs create distinct types that are not interchangeable with their underlying type
or with other typedefs of the same underlying type. They use `Dynamic_Object` internally and
automatically expose operators that the underlying type supports.

### Basic Usage

```
using Meters = int
using Seconds = int

var d = Meters(100)
var t = Seconds(10)

// d and t are distinct types — you cannot accidentally mix them
// Meters + Seconds would require an explicit conversion
```

### Arithmetic and Comparison

Operators from the underlying type are forwarded and remain strongly typed:

```
using Meters = int

var a = Meters(10)
var b = Meters(20)

var c = a + b // Meters(30) — result is still Meters
var bigger = b > a // true — comparisons return bool

// Compound assignment operators work too
a += b // a is now Meters(30)
```

### String-Based Strong Typedefs

Strong typedefs work with any type, not just numeric types:

```
using Name = string

var n = Name("Alice")
var greeting = Name("Hello, ") + Name("world") // Name — string concatenation is forwarded
```

### Accessing the Underlying Value

Use `to_underlying` to extract the wrapped value:

```
using Meters = int

var d = Meters(42)
var raw = to_underlying(d) // 42, plain int
```

### Extending Strong Typedefs

You can add custom operations to strong typedefs just like any other ChaiScript type:

```
using Meters = int
using Seconds = int
using MetersPerSecond = int

def speed(Meters d, Seconds t) {
MetersPerSecond(to_underlying(d) / to_underlying(t))
}

var s = speed(Meters(100), Seconds(10)) // MetersPerSecond(10)
```

You can also overload operators between different strong typedefs:

```
using Meters = int
using Feet = int

def to_feet(Meters m) {
Feet((to_underlying(m) * 328) / 100)
}

var m = Meters(10)
var f = to_feet(m) // Feet(32)
```

## method_missing

A function of the signature `method_missing(object, name, param1, param2, param3)` will be called if an appropriate
Expand Down
1 change: 1 addition & 0 deletions grammar/chaiscript.ebnf
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ enum_entry ::= id ( "=" integer )?

underlying_type ::= id


/* ---- Blocks & flow keywords ---- */

block ::= "{" statements* "}"
Expand Down
5 changes: 3 additions & 2 deletions include/chaiscript/language/chaiscript_common.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ namespace chaiscript {
template<typename T>
static bool is_reserved_word(const T &s) noexcept {
const static std::unordered_set<std::uint32_t>
words{utility::hash("def"), utility::hash("fun"), utility::hash("while"), utility::hash("for"), utility::hash("if"), utility::hash("else"), utility::hash("&&"), utility::hash("||"), utility::hash(","), utility::hash("auto"), utility::hash("return"), utility::hash("break"), utility::hash("true"), utility::hash("false"), utility::hash("class"), utility::hash("attr"), utility::hash("var"), utility::hash("global"), utility::hash("GLOBAL"), utility::hash("_"), utility::hash("__LINE__"), utility::hash("__FILE__"), utility::hash("__FUNC__"), utility::hash("__CLASS__"), utility::hash("const"), utility::hash("enum")};
words{utility::hash("def"), utility::hash("fun"), utility::hash("while"), utility::hash("for"), utility::hash("if"), utility::hash("else"), utility::hash("&&"), utility::hash("||"), utility::hash(","), utility::hash("auto"), utility::hash("return"), utility::hash("break"), utility::hash("true"), utility::hash("false"), utility::hash("class"), utility::hash("attr"), utility::hash("var"), utility::hash("global"), utility::hash("GLOBAL"), utility::hash("_"), utility::hash("__LINE__"), utility::hash("__FILE__"), utility::hash("__FUNC__"), utility::hash("__CLASS__"), utility::hash("const"), utility::hash("using"), utility::hash("enum")};

return words.count(utility::hash(s)) == 1;
}
Expand Down Expand Up @@ -107,6 +107,7 @@ namespace chaiscript {
Compiled,
Const_Var_Decl,
Const_Assign_Decl,
Using,
Enum,
Namespace_Block
};
Expand All @@ -129,7 +130,7 @@ namespace chaiscript {
namespace {
/// Helper lookup to get the name of each node type
constexpr const char *ast_node_type_to_string(AST_Node_Type ast_node_type) noexcept {
constexpr const char *const ast_node_types[] = {"Id", "Fun_Call", "Unused_Return_Fun_Call", "Arg_List", "Equation", "Var_Decl", "Assign_Decl", "Array_Call", "Dot_Access", "Lambda", "Block", "Scopeless_Block", "Def", "While", "If", "For", "Ranged_For", "Inline_Array", "Inline_Map", "Return", "File", "Prefix", "Break", "Continue", "Map_Pair", "Value_Range", "Inline_Range", "Try", "Catch", "Finally", "Method", "Attr_Decl", "Logical_And", "Logical_Or", "Reference", "Switch", "Case", "Default", "Noop", "Class", "Binary", "Arg", "Global_Decl", "Constant", "Compiled", "Const_Var_Decl", "Const_Assign_Decl", "Enum", "Namespace_Block"};
constexpr const char *const ast_node_types[] = {"Id", "Fun_Call", "Unused_Return_Fun_Call", "Arg_List", "Equation", "Var_Decl", "Assign_Decl", "Array_Call", "Dot_Access", "Lambda", "Block", "Scopeless_Block", "Def", "While", "If", "For", "Ranged_For", "Inline_Array", "Inline_Map", "Return", "File", "Prefix", "Break", "Continue", "Map_Pair", "Value_Range", "Inline_Range", "Try", "Catch", "Finally", "Method", "Attr_Decl", "Logical_And", "Logical_Or", "Reference", "Switch", "Case", "Default", "Noop", "Class", "Binary", "Arg", "Global_Decl", "Constant", "Compiled", "Const_Var_Decl", "Const_Assign_Decl", "Using", "Enum", "Namespace_Block"};

return ast_node_types[static_cast<int>(ast_node_type)];
}
Expand Down
Loading
Loading