val
99 |
14 |
15 | ## Installation
16 |
17 | `val` should run on any system, including Linux, MacOS, and the BSDs.
18 |
19 | The easiest way to install it is by using [cargo](https://doc.rust-lang.org/cargo/index.html),
20 | the Rust package manager:
21 |
22 | ```bash
23 | cargo install val
24 | ```
25 |
26 | Otherwise, see below for the complete package list:
27 |
28 | #### Cross-platform
29 |
30 | | Package Manager | 34 |Package | 35 |Command | 36 |
|---|---|---|
| Cargo | 41 |val | 42 |cargo install val |
43 |
| Homebrew | 46 |terror/tap/val | 47 |brew install terror/tap/val |
48 |
a || b | true || false |
179 | | | Not | `!a` | `!true` |
180 | | **Comparison** | Equal | `a == b` | `x == 10` |
181 | | | Not Equal | `a != b` | `y != 20` |
182 | | | Less Than | `a < b` | `a < b` |
183 | | | Less Than or Equal | `a <= b` | `i <= 5` |
184 | | | Greater Than | `a > b` | `count > 0` |
185 | | | Greater Than or Equal | `a >= b` | `value >= 100` |
186 | | **Other** | Function Call | `function(args)` | `sin(x)` |
187 | | | List Indexing | `list[index]` | `numbers[0]` |
188 | | | List Creation | `[item1, item2, ...]` | `[1, 2, 3]` |
189 | | | List Concatenation | `list1 + list2` | `[1, 2] + [3, 4]` |
190 | | | String Concatenation | `string1 + string2` | `"Hello, " + name` |
191 | | | Variable Reference | `identifier` | `x` |
192 |
193 | ### Values
194 |
195 | **val** has several primitive value types:
196 |
197 | #### Number
198 |
199 | Numeric values are represented as arbitrary precision floating point numbers (using
200 | [astro_float](https://docs.rs/astro-float/latest/astro_float/index.html) under
201 | the hood):
202 |
203 | ```rust
204 | > pi
205 | 3.141592653589793115997963468544185161590576171875
206 | > e
207 | 2.718281828459045090795598298427648842334747314453125
208 | > sin(2) * e ^ pi * cos(sum([1, 2, 3]))
209 | 16.4814557939128835908118223753548409318930600432600320575175542910885566534716862696709583557263450637540094805515971245058657340687939442764118452427864231041058959960049996970569867866035825048029794926250103816423751837050040821914044725396611746570949840536443560831710407959633707222226883928822125018007
210 | >
211 | ```
212 |
213 | You can specify the rounding mode, and what sort of precision you'd like to see
214 | in the output by using the `--rounding-mode` and `--precision` options (note
215 | that `--precision` controls binary precision, measured in bits, not decimal
216 | digits).
217 | respectively.
218 |
219 | #### Boolean
220 |
221 | Boolean values represent truth values:
222 |
223 | ```rust
224 | a = true
225 | b = false
226 | c = a && b
227 | d = a || b
228 | e = !a
229 | ```
230 |
231 | #### String
232 |
233 | Text values enclosed in single or double quotes:
234 |
235 | ```rust
236 | greeting = "Hello"
237 | name = 'World'
238 | message = greeting + ", " + name + "!"
239 | ```
240 |
241 | #### List
242 |
243 | Collections of values of any type:
244 |
245 | ```rust
246 | numbers = [1, 2, 3, 4, 5]
247 | mixed = [1, "two", true, [3, 4]]
248 | empty = []
249 | first = numbers[0]
250 | numbers[0] = 10
251 | combined = numbers + [6, 7]
252 | ```
253 |
254 | #### Function
255 |
256 | A function is a value, and can be used in assignments, passed around to other
257 | functions, etc.
258 |
259 | Check out the [higher order functions example](https://github.com/terror/val/blob/master/examples/hoc.val)
260 | for how this works.
261 |
262 | ```rust
263 | fn reduce(l, f, initial) {
264 | i = 0
265 |
266 | result = initial
267 |
268 | while (i < len(l)) {
269 | result = f(result, l[i])
270 | i = i + 1
271 | }
272 |
273 | return result
274 | }
275 |
276 | fn sum(a, b) {
277 | return a + b
278 | }
279 |
280 | l = [1, 2, 3, 4, 5]
281 |
282 | println(reduce(l, sum, 0))
283 | ```
284 |
285 | #### Null
286 |
287 | Represents the absence of a value.
288 |
289 | ```rust
290 | fn search(l, x) {
291 | i = 0
292 |
293 | while (i < len(l)) {
294 | if (l[i] == x) {
295 | return i
296 | }
297 |
298 | i = i + 1
299 | }
300 | }
301 |
302 | l = [1, 2, 3, 4, 5]
303 |
304 | index = search(l, 6)
305 |
306 | if (index == null) {
307 | println("Value not found")
308 | } else {
309 | println("Value found at index " + index)
310 | }
311 | ```
312 |
313 | ### Built-ins
314 |
315 | **val** offers a many built-in functions and constants:
316 |
317 | | Category | Function/Constant | Description | Example |
318 | | ----------------- | ------------------- | ---------------------------------- | ------------------------ |
319 | | **Constants** | `pi` | Mathematical constant π (≈3.14159) | `area = pi * r^2` |
320 | | | `e` | Mathematical constant e (≈2.71828) | `growth = e^rate` |
321 | | | `phi` | Golden ratio φ (≈1.61803) | `ratio = phi * width` |
322 | | | `tau` | Tau constant τ (≈6.28318, 2π) | `circum = tau * r` |
323 | | **Trigonometric** | `sin(x)` | Sine of x (radians) | `sin(pi/2)` |
324 | | | `cos(x)` | Cosine of x (radians) | `cos(0)` |
325 | | | `tan(x)` | Tangent of x (radians) | `tan(pi/4)` |
326 | | | `csc(x)` | Cosecant of x (radians) | `csc(pi/6)` |
327 | | | `sec(x)` | Secant of x (radians) | `sec(0)` |
328 | | | `cot(x)` | Cotangent of x (radians) | `cot(pi/4)` |
329 | | **Inverse Trig** | `asin(x)` | Arc sine (-1≤x≤1) | `asin(0.5)` |
330 | | | `acos(x)` | Arc cosine (-1≤x≤1) | `acos(0.5)` |
331 | | | `arc(x)` | Arc tangent | `arc(1)` |
332 | | | `acsc(x)` | Arc cosecant (abs(x)≥1) | `acsc(2)` |
333 | | | `asec(x)` | Arc secant (abs(x)≥1) | `asec(2)` |
334 | | | `acot(x)` | Arc cotangent | `acot(1)` |
335 | | **Hyperbolic** | `sinh(x)` | Hyperbolic sine | `sinh(1)` |
336 | | | `cosh(x)` | Hyperbolic cosine | `cosh(1)` |
337 | | | `tanh(x)` | Hyperbolic tangent | `tanh(1)` |
338 | | **Logarithmic** | `ln(x)` | Natural logarithm | `ln(e)` |
339 | | | `log2(x)` | Base-2 logarithm | `log2(8)` |
340 | | | `log10(x)` | Base-10 logarithm | `log10(100)` |
341 | | | `e(x)` | e raised to power x | `e(2)` |
342 | | **Numeric** | `sqrt(x)` | Square root (x≥0) | `sqrt(16)` |
343 | | | `ceil(x)` | Round up to integer | `ceil(4.3)` |
344 | | | `floor(x)` | Round down to integer | `floor(4.7)` |
345 | | | `abs(x)` | Absolute value | `abs(-5)` |
346 | | | `gcd(a, b)` | Greatest common divisor | `gcd(12, 8)` |
347 | | | `lcm(a, b)` | Least common multiple | `lcm(4, 6)` |
348 | | **Collections** | `len(x)` | Length of list or string | `len("hello")` |
349 | | | `sum(list)` | Sum list elements | `sum([1,2,3])` |
350 | | | `append(list, val)` | Add element to end of list | `append([1,2], 3)` |
351 | | **Conversion** | `int(x)` | Convert to integer | `int("42")` |
352 | | | `float(x)` | Convert to float | `float("3.14")` |
353 | | | `bool(x)` | Convert to boolean | `bool(1)` |
354 | | | `list(x)` | Convert to list | `list("abc")` |
355 | | **I/O** | `print(...)` | Print without newline | `print("Hello")` |
356 | | | `println(...)` | Print with newline | `println("World")` |
357 | | | `input([prompt])` | Read line from stdin | `name = input("Name: ")` |
358 | | **String** | `split(str, delim)` | Split string | `split("a,b,c", ",")` |
359 | | | `join(list, delim)` | Join list elements | `join(["a","b"], "-")` |
360 | | **Program** | `exit([code])` | Exit program | `exit(1)` |
361 | | | `quit([code])` | Alias for exit | `quit(0)` |
362 |
363 | ## Prior Art
364 |
365 | [bc(1)](https://linux.die.net/man/1/bc) - An arbitrary precision calculator
366 | language
367 |
--------------------------------------------------------------------------------
/src/highlighter.rs:
--------------------------------------------------------------------------------
1 | use super::*;
2 |
3 | const COLOR_BOOLEAN: &str = "\x1b[33m"; // Yellow
4 | const COLOR_ERROR: &str = "\x1b[31m"; // Red
5 | const COLOR_FUNCTION: &str = "\x1b[34m"; // Blue
6 | const COLOR_IDENTIFIER: &str = "\x1b[37m"; // White
7 | const COLOR_KEYWORD: &str = "\x1b[35m"; // Magenta
8 | const COLOR_NUMBER: &str = "\x1b[33m"; // Yellow
9 | const COLOR_OPERATOR: &str = "\x1b[36m"; // Cyan
10 | const COLOR_RESET: &str = "\x1b[0m";
11 | const COLOR_STRING: &str = "\x1b[32m"; // Green
12 |
13 | pub struct TreeHighlighter<'src> {
14 | content: &'src str,
15 | }
16 |
17 | impl<'src> TreeHighlighter<'src> {
18 | pub fn new(content: &'src str) -> Self {
19 | Self { content }
20 | }
21 |
22 | pub fn highlight(&self) -> Cow<'src, str> {
23 | match parse(self.content) {
24 | Ok(ast) => self.colorize_ast(&ast),
25 | Err(_) => {
26 | Owned(format!("{}{}{}", COLOR_ERROR, self.content, COLOR_RESET))
27 | }
28 | }
29 | }
30 |
31 | fn colorize_ast(&self, program: &Spanned