-
Notifications
You must be signed in to change notification settings - Fork 3
/
ylilisp.txt
149 lines (129 loc) · 5.06 KB
/
ylilisp.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
YliLisp is the scripting language of Ylikuutio.
YliLisp is influenced by Scheme, Common Lisp, C++,
AngelScript, and Rust.
Use cases:
* Defining physics simulations.
* Defining game scenes.
* In-simulation console.
* In-game console.
* NPC AI.
* Scripted game events.
* Game modding.
General features:
* Lexically scoped.
* Variables and functions in the same namespace (Lisp-1).
* Mutators marked with `!` like in Scheme, e.g. `set!`.
* Predicates marked with `?` like in Scheme, e.g. `null?`.
* Common function names follow names used by Scheme.
* All objects, both variables and functions,
are `yli::ontology::Entity` entities.
* `yli::ontology::Entity` entities with global names
are global YliLisp variables with the same name.
* YliLisp syntax follows Scheme syntax when possible
considering other YliLisp design goals.
Numeric types:
* Test if variable is a number: `(number? 1)` -> `#t`
* Test if variable is a number: `(number? 'foo)` -> `#f`
* Test if variable is a number: `(number? '(1 2 3))` -> `#f`
* Test if variable is a number: `(number? '#(1 2 3))` -> `#f`
Integer types:
* Statically typed: `(define my-number 'uint64 123)`.
* Type conversion must be explicit: `(as 'uint64 my-number)`.
* `cast` can only be used for converting into wider variables
where the value always fits in the new type.
* When overflow, precision loss or truncation could occur
`try-cast` needs to be used: `(try-as 'int8 my-number)`.
* If number does not fit in the type, `try-as` will throw.
* The default type for integer literals is `int32`.
* An integer literal that does not fit in `int32` causes
a compiler error.
* Different types for integer literals for can be given:
`'int64 123`.
* Integer variable types: `int8`, `int16`, `int32`, `int64`,
`uint8`, `uint16`, `uint32`, `uint64`.
Floating point types:
* `float`, `double`.
Boolean types:
* `bool`.
Lists:
* List syntax: `(list 1 2 3)`.
* List syntax (syntactic sugar): `'(1 2 3)`.
* Test if variable is a list: `(list? 'foo)` -> `#f`
* Test if variable is a list: `(list? '(1 2 3))` -> `#t`
* Test if variable is a list: `(list? '#(1 2 3))` -> `#f`
Vectors:
* Vector syntax: `(vector 1 2 3)`.
* Vector syntax (syntactic sugar): `#(1 2 3)`.
* Test if variable is a vector: `(vector? 'foo)` -> `#f`
* Test if variable is a vector: `(vector? '(1 2 3))` -> `#f`
* Test if variable is a vector: `(vector? '#(1 2 3))` -> `#t`
Structs:
* Struct syntax: `(struct foo)`.
* Member syntax: `(member (member foo 'bar) 'baz)`.
* Member syntax: `(member (member foo "bar") "baz")`.
* Struct syntax (syntactic sugar): `foo.bar.baz`
(whitespace around dot operators is free).
* Generic setter can be used for struct members as well:
`(set! (member foo bar) 123)`.
Parents and children:
* `(child (child foo 'bar) 'baz)`.
* `(child (child foo "bar") "baz")`.
* Syntactic sugar: `foo.bar.baz`
Masters and apprentices:
* `(apprentice (apprentice foo 'bar) 'baz)`.
* `(apprentice (apprentice foo "bar") "baz")`.
* Syntactic sugar: `foo:bar:baz`
Indexing:
* Indexing syntax: `(nth foo bar)`
* Indexing syntax (syntactic sugar): `foo[bar]`.
(whitespace around square bracket operators is free).
Functions:
* Functions are first-class citizens.
* Functions can be overloaded.
* Member functions/methods are supported as well:
`(foo.bar)`, `(foo.bar baz)`, etc.
References and borrowing:
* Reference syntax: `(ref foo)`.
* Reference syntax (syntactic sugar): `&foo`.
* Mutable reference syntax: `(mut-ref foo)`.
* Mutable reference syntax (syntactic sugar): `&mut foo`.
Pointers:
* `null` is a null pointer.
Literals:
* Underscore `_` can be used for readability in numeric literals.
Comments:
* `;` starts a comment until end of line.
* `//` also starts a comment until end of line.
* `/*` ... `*/` can be used for block comments.
Planned implementation details:
* Functions are `yli::ontology::LispFunction`,
which inherits `yli::ontology::Entity`.
* Function overloads are implemented by a
class template `yli::ontology::LispFunctionOverload`,
which inherits `yli::ontology::GenericLispFunctionOverload`,
a non-template class.
* `yli::ontology::GenericLispFunctionOverload` inherits
`yli::ontology::Entity`.
* Lambda expressions are `yli::ontology::Lambda`,
which inherits `yli::ontology::Entity`.
* S-expressions are `yli::ontology::Sexp`,
which inherits `yli::ontology::Entity`.
* Each `yli::ontology::Console` may register
YliLisp functions into its local context,
similarly to AngelScript.
* All variables are always available in all contexts.
* Ylikuutio uses a C++ exception handler to handle
exceptions triggered by execution of YliLisp code.
* When an exception occurs, the effects caused by already
executed YliLisp code are undone by setting and
activating the old values stored on each change.
Command examples:
* `(define my-uint16 'uint64 123)`.
* `(define my-int32 (cast my-uint64 'int8))`.
* `(define my-uint64 'uint64 123)`.
* `(define my-int8 (try-cast my-uint64 'int8))`.
* `(define my-float 'float 3.14)`.
* `(define my-double (cast my-float 'double))`.
Links:
* https://compilers.iecc.com/crenshaw/
* https://craftinginterpreters.com/