https://github.com/eignnx/funlang
A programming language similar to OCaml and Rust with Ruby-inspired syntax.
https://github.com/eignnx/funlang
bytecode-interpreter programming-language
Last synced: 9 months ago
JSON representation
A programming language similar to OCaml and Rust with Ruby-inspired syntax.
- Host: GitHub
- URL: https://github.com/eignnx/funlang
- Owner: eignnx
- License: other
- Created: 2021-06-30T01:54:48.000Z (over 4 years ago)
- Default Branch: main
- Last Pushed: 2023-06-22T03:46:58.000Z (over 2 years ago)
- Last Synced: 2025-01-21T17:35:41.446Z (11 months ago)
- Topics: bytecode-interpreter, programming-language
- Language: Haskell
- Homepage:
- Size: 296 KB
- Stars: 0
- Watchers: 2
- Forks: 0
- Open Issues: 4
-
Metadata Files:
- Readme: README.md
- Changelog: ChangeLog.md
- License: LICENSE
Awesome Lists containing this project
README
# Funlang
It's a fun language-side-project (not that I have a real project to work on tho).
## What it Looks Like
```ruby
type NamedColor
| :Red
| :Green
| :Blue
| :Cyan
| :Magenta
| :Yellow
| :Black
| :White
end
type Color
| :Rgb Int, Int, Int
| :Hsb Int, Int, Int
| NamedColor
end
def main[] do
let green = { :Green } as NamedColor;
let color = { :Rgb 50, 100, 200 } as Color;
color = green; # Note: allowed because NamedColor <: Color.
match color
| { :Red } => intr.puts["I love red!"]
| { :Rgb r, g, b } =>
intr.puts["The red component is"]; intr.dbg_int[r];
intr.puts["The green component is"]; intr.dbg_int[g];
intr.puts["The blue component is"]; intr.dbg_int[b];
| other => intr.puts["I don't know that color!"];
end
end
```
### Longer Example
```ruby
type rec Expr
| :Num Int
| :Bool Bool
| :Add rec, rec
| :Mul rec, rec
| :If rec, rec, rec
| :Var Text
| :Let Text, rec, rec
end
# Note: `Val` and `Expr` are allowed to have overlapping constructor names!
type Val
| :Num Int
| :Bool Bool
end
type rec Ctx
| :Empty
| :Bind Text, Val, rec
end
def eval[ctx: Ctx, expr: Expr] -> Tuple[Ctx, Val] do
match expr
| { :Num x } => { ctx, { :Num x } }
| { :Bool x } => { ctx, { :Bool x } }
| { :Add x, y } =>
let { ctx, x } = eval[ctx, x];
let { ctx, y } = eval[ctx, y];
let { :Num x } = x else
type_error["The `+` operator requires numbers!"];
end
let { :Num y } = y else
type_error["The `+` operator requires numbers!"];
end
{ ctx, { :Num x + y } }
| { :Mul x, y } =>
let { ctx, x } = eval[ctx, x];
let { ctx, y } = eval[ctx, y];
let { :Num x } = x else
type_error["The `*` operator requires numbers!"];
end
let { :Num y } = y else
type_error["The `*` operator requires numbers!"];
end
{ ctx, { :Num x * y } }
| { :If cond, yes, no } =>
let { ctx, cond } = eval[ctx, cond];
let { :Bool cond } = cond else
type_error["An `if` expression requires a boolean in it's conditional!"];
end
if cond then
eval[ctx, yes]
else
eval[ctx, no]
end
| { :Var x } => { ctx, ctx_lookup[ctx, x] }
| { :Let x, expr, body } =>
let { ctx, val } = eval[ctx, expr];
let ctx = { :Bind x, val, ctx };
eval[ctx, body]
end
end
def ctx_lookup[ctx: Ctx, x: Text] -> Val do
match ctx
| { :Empty } =>
intr.puts["Unbound variable " ++ x];
intr.exit[];
| { :Bind y, val, ctx } =>
if intr.eq_text[y, x] then
val
else
ctx_lookup[ctx, x]
end
end
end
def type_error[msg: Text] -> Never do
intr.puts["Type Error: " ++ msg];
intr.exit[];
end
def print_val[val: Val] do
match val
| { :Num x } => intr.dbg_int[x]
| { :Bool x } => intr.dbg_bool[x]
end
end
def main[] do
let ctx = { :Empty };
let expr =
{ :Let "x", { :Num 123 },
{ :Add { :Mul { :Num 2 }, { :Num 3 } }, { :Var "x" } } };
let { ctx, result } = eval[ctx, expr];
print_val[result];
end
```
## Build/Run Instructions
### Dependencies
- You need `stack` installed. I'm using version `2.9.3` just FYI.
- `Stack` should be using `ghc-8.10.4` for the haskell compiler.
- You need `cargo` to run the Rust bytecode interpreter.
### Running a Source File
```bash
$ stack run -- path/to/my/source-file.funlang
```
## Features/TODO
- [X] Compile a (somewhat) high-level language down to bytecode that can be run on a virtual machine
- [X] Impl basic operations, and control flow statements
- [X] Impl function calls
- [ ] Impl lexical scoping for blocks
- [ ] Impl closures
- [ ] Add a bidirectional type-checking algorithm
- [X] Implement non-polymorphic type checking
- [ ] Implement polymorphic type checking
- [ ] Add algebraic data types
- [X] Impl basic variant types
- [X] Impl tuple types
- [X] Impl record types (currently called Mod types)
- [ ] Call them records instead
- [X] Allow recursive types
- [ ] Impl `match` expressions
- [X] Support basic pattern matching
- [ ] Allow irrefutable patterns in `match` expressions
- [ ] Impl literal patterns
- [ ] Impl pattern guards
- [X] Impl `let-else` expressions