[YAML, fun]
Just an experimental project implementing embedded functional scripting language based on YAML syntax.
API docs for the standard library: src/Std.
Concept
Code:
:let:
(+):
:lambda: [x, y]
:do:
:+: [x, y]
(==):
:lambda: [x, y]
:do:
:==: [x, y]
Maybe:
:rec:
map:
:lambda: [callback, val]
:do:
:if: [(==), val, { :: null }]
:then: val
:else: [callback, val]
withDefault:
:lambda: [default, val]
:do:
:if: [(==), val, { :: null }]
:then: default
:else: val
Cons:
:rec:
new:
:lambda: [a, b, op]
:do: [op, a, b]
car:
:lambda: [cons]
:do:
- cons
- :lambda: [a, b]
:do: a
cdr:
:lambda: [cons]
:do:
- cons
- :lambda: [a, b]
:do: b
cons: [Cons.new, { :: 1 }, { :: 2 }]
foobar:
- (++)
- { :: foo }
- { :: bar }
things:
- (++)
- :list:
- foobar
- cons
- Maybe
- [Cons.car, cons]
- :: [1, 1.2, -9, null, bar]
:in:
:rec:
a: [Maybe.map, [(+), { :: 1 }], { :: 5 }]
b: [Maybe.map, [(+), { :: 1 }], { :: null }]
c: [Maybe.withDefault, { :: 0 }, { :: null }]
d:
- [Maybe.withDefault, { :: 0 }]
- - [Maybe.map, [(+), { :: 1 }]]
- - [Maybe.map, [(+), { :: 1 }]]
- { :: 10 }
e:
:|>:
- { :: 10 }
- [Maybe.map, [(+), { :: 1 }]]
- [Maybe.map, [(+), { :: 1 }]]
- [Maybe.withDefault, { :: 0 }]
f: [Cons.car, cons]
g: [Cons.cdr, cons]
h: [List.head, things]
i:
:|>:
- [List.tail, things]
- List.head
- Cons.car
Result:
{a: 6, b: null, c: 0, d: 12, e: 12, f: 1, g: 2, h: "foobar", i: 1}
Things that (probably) work
Constant
:: foo
Variable
foo
Function
:lambda: [num1, num2]
:do:
:+: [num1, num2]
Function Call
[func, arg1, arg2]
Chaining
:|>:
- { :: 1 }
- [(+), { :: 5 }]
- [(+), { :: 4 }]
Record
:rec:
a:
:rec:
b: { :: { 1: bar, true: baz } }
'10': { :: foo }
e: { :: { y: z } }
Record Field Access
foo.a.10
foo.a.b.(1)
:get: [foo, { :: a }, { :: b }, { :: 1 }]
Record Field Update
:update: foo
:set:
a: { :: bar }
oldFoo: foo
:unset: [e]
List
:list:
- { :: a }
- { :: 1 }
- { :: 1.1 }
- { :: -1 }
- { :: true }
- :list:
- { :: nested }
If Else
:if:
:==: [:: 2, :: 2]
:then: { :: yes }
:else: { :: no }
Let In
:let:
a: { :: foo }
b: a
:in: b
With
:let:
args1:
:rec:
first: { :: 10 }
second: { :: 20 }
args2:
::
third: 30
:in:
:with: [args1, args2]
:do:
:+: [first, second, third]
Case Of
:let:
handle:
:lambda: [var]
:do:
:case: var
:of:
:==:
1: { :: this is one }
[]: { :: this is empty list }
bar: { :: this is bar }
:(): { :: this null }
:bool:
:as: [b]
:do: { :: this is a bool }
:int:
:as: [n]
:do: { :: this is an int }
:float:
:as: [f]
:do: { :: this is a float }
:string:
:as: [first, rest]
:do: first
:function:
:as: [f]
:do: { :: this is a function }
:list:
:as: [head, tail]
:do: head
:rec:
:as: [r]
:do: r.foo
:_:
:as: [wtf]
:do: { :: 'wtf??' }
:in:
:list:
- [handle, { :: null }]
- [handle, { :: true }]
- [handle, { :: 1 }]
- [handle, { :: 2 }]
- [handle, { :: 1.1 }]
- [handle, { :: foo }]
- [handle, { :: bar }]
- [handle, handle]
- [handle, { :: [] }]
- [handle, { :: [a, b] }]
- [handle, { :: { foo: bar } }]
Platform Call
:platform: import
:arg: { :: ./concept.yml }
struct MyPlatform(DefaultPlatform);
impl Platform for MyPlatform { ... }
fn main() {
let vm = Vm::new(MyPlatform(DefaultPlatform)).unwrap();
...
}
Embed into Rust
Contribute
See CONTRIBUTING.md