Skip to content

Commit 4be837b

Browse files
committed
🎉 Inititial commit
0 parents  commit 4be837b

File tree

12 files changed

+670
-0
lines changed

12 files changed

+670
-0
lines changed

‎.github/workflows/test.yml

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
name: test
2+
3+
on:
4+
push:
5+
branches:
6+
- master
7+
- main
8+
pull_request:
9+
10+
jobs:
11+
test:
12+
runs-on: ubuntu-latest
13+
steps:
14+
- uses: actions/checkout@v3
15+
- uses: erlef/setup-beam@v1
16+
with:
17+
otp-version: "26.0.2"
18+
gleam-version: "1.0.0"
19+
rebar3-version: "3"
20+
# elixir-version: "1.15.4"
21+
- run: gleam deps download
22+
- run: gleam test
23+
- run: gleam format --check src test

‎.gitignore

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
*.beam
2+
*.ez
3+
/build
4+
erl_crash.dump

‎README.md

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# spark
2+
3+
[![Package Version](https://img.shields.io/hexpm/v/spark)](https://hex.pm/packages/spark)
4+
[![Hex Docs](https://img.shields.io/badge/hex-docs-ffaff3)](https://hexdocs.pm/spark/)
5+
6+
```sh
7+
gleam add spark
8+
```
9+
```gleam
10+
import spark
11+
12+
pub fn main() {
13+
// TODO: An example of the project in use
14+
}
15+
```
16+
17+
Further documentation can be found at <https://hexdocs.pm/spark>.
18+
19+
## Development
20+
21+
```sh
22+
gleam run # Run the project
23+
gleam test # Run the tests
24+
gleam shell # Run an Erlang shell
25+
```

‎gleam.toml

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
name = "spark"
2+
version = "1.0.0"
3+
4+
# Fill out these fields if you intend to generate HTML documentation or publish
5+
# your project to the Hex package manager.
6+
#
7+
# description = ""
8+
# licences = ["Apache-2.0"]
9+
# repository = { type = "github", user = "username", repo = "project" }
10+
# links = [{ title = "Website", href = "https://gleam.run" }]
11+
#
12+
# For a full reference of all the available options, you can have a look at
13+
# https://gleam.run/writing-gleam/gleam-toml/.
14+
15+
[dependencies]
16+
gleam_stdlib = "~> 0.34 or ~> 1.0"
17+
nibble = "~> 1.1"
18+
19+
[dev-dependencies]
20+
gleeunit = "~> 1.0"
21+
pprint = "~> 1.0"

‎grammar.md

+90
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
The following is the current grammar specification of Spark. Since it's a specification, the implementation may not be completely up to speed with it.
2+
3+
> todo: atoms, atom patterns, of operator, named patterns, module imports, dot notation for modules, backpassing
4+
5+
```ebnf
6+
(* Module *)
7+
8+
module = declaration* -> Module ;
9+
10+
(* Declarations *)
11+
12+
declaration
13+
= function -> Function
14+
| constant -> Const
15+
| external -> TopLevelExternal
16+
;
17+
18+
function = "def" ["pub"] IDENT "\\" [comma_sep<IDENT>] "=" expression ;
19+
20+
constant = "const" ["pub"] IDENT "=" expression ;
21+
22+
(* Expressions *)
23+
24+
expression
25+
= ops
26+
| lambda -> Lambda
27+
| let -> Let
28+
| case -> Case
29+
;
30+
31+
ops
32+
= nibble.pratt<
33+
one_of = call ;
34+
and_then
35+
= ?prefix 9? ("-" | "!")
36+
| ?infix_right 8? "^"
37+
| ?infix_left 7? ("*" | "/")
38+
| ?infix_left 6? ("+" | "-")
39+
| ?infix_left 5? ("<" | ">" | "<=" | ">=")
40+
| ?infix_left 4? ("==" | "!=")
41+
| ?infix_left 3? "and"
42+
| ?infix_left 2? "or"
43+
| ?infix_right 1? ":"
44+
| ?infix_left 0? ";"
45+
;
46+
>
47+
;
48+
49+
(* calls have the highest precedence but are not in the pratt parser since they aren't really operators *)
50+
call = primary {"(" [comma_sep<expression>] ")"} ;
51+
52+
primary
53+
=
54+
| NUMBER -> Number
55+
| STRING -> String
56+
| IDENT -> Variable
57+
| list -> List
58+
| external -> External
59+
| "(" expression ")"
60+
;
61+
62+
list = "[" [comma_sep<expression>] "]" ;
63+
64+
external = "external" STRING ;
65+
66+
lambda = "\\" comma_sep<IDENT> "->" expression ;
67+
68+
let = "let" Ident "=" expression "in" expression ;
69+
70+
case = "case" expression ("|" pattern "=" expression)+ ;
71+
72+
(* Patterns *)
73+
74+
pattern
75+
= list_pattern -> ListPattern
76+
| "_" -> IgnorePattern
77+
| IDENT -> VariablePattern
78+
| NUMBER -> NumberPattern
79+
| STRING -> StringPattern
80+
;
81+
82+
list_pattern
83+
= "[" [comma_sep<pattern>] "]"
84+
| "[" comma_sep<pattern> [":" IDENT] "]"
85+
;
86+
87+
(* Helpers *)
88+
89+
comma_sep<rule> = rule {"," rule} ;
90+
```

‎manifest.toml

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# This file was generated by Gleam
2+
# You typically do not need to edit this file
3+
4+
packages = [
5+
{ name = "argv", version = "1.0.2", build_tools = ["gleam"], requirements = [], otp_app = "argv", source = "hex", outer_checksum = "BA1FF0929525DEBA1CE67256E5ADF77A7CDDFE729E3E3F57A5BDCAA031DED09D" },
6+
{ name = "birdie", version = "1.1.0", build_tools = ["gleam"], requirements = ["argv", "filepath", "gap", "glance", "gleam_community_ansi", "gleam_erlang", "gleam_stdlib", "gleeunit", "justin", "rank", "simplifile", "trie_again"], otp_app = "birdie", source = "hex", outer_checksum = "DE7BEE4C76A52E91E72800531B6E5B41093D06FA90C7F6D9FDE768BCE714FAA7" },
7+
{ name = "filepath", version = "0.2.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "filepath", source = "hex", outer_checksum = "FC1B1B29438A5BA6C990F8047A011430BEC0C5BA638BFAA62718C4EAEFE00435" },
8+
{ name = "gap", version = "1.1.3", build_tools = ["gleam"], requirements = ["gleam_community_ansi", "gleam_stdlib"], otp_app = "gap", source = "hex", outer_checksum = "6EF5E3B523FDFBC317E9EA28D5163EE04744A97C007106F90207569789612291" },
9+
{ name = "glam", version = "2.0.0", build_tools = ["gleam"], requirements = ["birdie", "gleam_stdlib"], otp_app = "glam", source = "hex", outer_checksum = "1C10BE5EA72659E409DC2325BA5E94E0CC92C6C50B2A1DBADE6D07E8C9484D51" },
10+
{ name = "glance", version = "0.8.2", build_tools = ["gleam"], requirements = ["gleam_stdlib", "glexer"], otp_app = "glance", source = "hex", outer_checksum = "ACF09457E8B564AD7A0D823DAFDD326F58263C01ACB0D432A9BEFDEDD1DA8E73" },
11+
{ name = "gleam_community_ansi", version = "1.4.0", build_tools = ["gleam"], requirements = ["gleam_community_colour", "gleam_stdlib"], otp_app = "gleam_community_ansi", source = "hex", outer_checksum = "FE79E08BF97009729259B6357EC058315B6FBB916FAD1C2FF9355115FEB0D3A4" },
12+
{ name = "gleam_community_colour", version = "1.4.0", build_tools = ["gleam"], requirements = ["gleam_json", "gleam_stdlib"], otp_app = "gleam_community_colour", source = "hex", outer_checksum = "795964217EBEDB3DA656F5EB8F67D7AD22872EB95182042D3E7AFEF32D3FD2FE" },
13+
{ name = "gleam_erlang", version = "0.25.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_erlang", source = "hex", outer_checksum = "054D571A7092D2A9727B3E5D183B7507DAB0DA41556EC9133606F09C15497373" },
14+
{ name = "gleam_json", version = "1.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib", "thoas"], otp_app = "gleam_json", source = "hex", outer_checksum = "8B197DD5D578EA6AC2C0D4BDC634C71A5BCA8E7DB5F47091C263ECB411A60DF3" },
15+
{ name = "gleam_stdlib", version = "0.36.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "C0D14D807FEC6F8A08A7C9EF8DFDE6AE5C10E40E21325B2B29365965D82EB3D4" },
16+
{ name = "gleeunit", version = "1.0.2", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "D364C87AFEB26BDB4FB8A5ABDE67D635DC9FA52D6AB68416044C35B096C6882D" },
17+
{ name = "glexer", version = "0.7.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "glexer", source = "hex", outer_checksum = "4484942A465482A0A100936E1E5F12314DB4B5AC0D87575A7B9E9062090B96BE" },
18+
{ name = "justin", version = "1.0.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "justin", source = "hex", outer_checksum = "7FA0C6DB78640C6DC5FBFD59BF3456009F3F8B485BF6825E97E1EB44E9A1E2CD" },
19+
{ name = "nibble", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "nibble", source = "hex", outer_checksum = "2D9045E2CB12421783745113FD74DAC593EE3C2CCB74EA56E981ACEC0D442C20" },
20+
{ name = "pprint", version = "1.0.0", build_tools = ["gleam"], requirements = ["glam", "gleam_stdlib"], otp_app = "pprint", source = "hex", outer_checksum = "2764575188B81F2AE1F9AFE57308B7078CA27EBE2AC797EBA272017550B5CF31" },
21+
{ name = "rank", version = "1.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "rank", source = "hex", outer_checksum = "5660E361F0E49CBB714CC57CC4C89C63415D8986F05B2DA0C719D5642FAD91C9" },
22+
{ name = "simplifile", version = "1.5.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "simplifile", source = "hex", outer_checksum = "C44DB387524F90DC42142699C78C850003289D32C7C99C7D32873792A299CDF7" },
23+
{ name = "thoas", version = "0.4.1", build_tools = ["rebar3"], requirements = [], otp_app = "thoas", source = "hex", outer_checksum = "4918D50026C073C4AB1388437132C77A6F6F7C8AC43C60C13758CC0ADCE2134E" },
24+
{ name = "trie_again", version = "1.1.2", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "trie_again", source = "hex", outer_checksum = "5B19176F52B1BD98831B57FDC97BD1F88C8A403D6D8C63471407E78598E27184" },
25+
]
26+
27+
[requirements]
28+
gleam_stdlib = { version = "~> 0.34 or ~> 1.0" }
29+
gleeunit = { version = "~> 1.0" }
30+
nibble = { version = "~> 1.1" }
31+
pprint = { version = "~> 1.0" }

‎src/spark.gleam

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import gleam/io
2+
import spark/lexer
3+
import spark/parser
4+
import pprint
5+
6+
pub fn main() {
7+
let assert Ok(tokens) =
8+
lexer.lex("
9+
const math = 1 + 2 * 3 + 4 / 5 : 2 : 3
10+
const pub test = [1, 2, [3], 4]
11+
12+
external \"import fs from 'node:fs';\"
13+
14+
const foo = external \"blah blah\"
15+
16+
def add\\a, b =
17+
a + b
18+
19+
const test = blah(1, (), 2)")
20+
21+
parser.parse(tokens)
22+
|> pprint.debug
23+
io.println("Hello from spark!")
24+
}

‎src/spark/ast.gleam

+101
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
//// This module contains the AST of spark. Everything representable in spark
2+
//// is represented here in some way.
3+
////
4+
5+
import gleam/option.{type Option}
6+
7+
/// A module contains multiple top-level declarations.
8+
///
9+
pub type Module {
10+
Module(declarations: List(Declaration))
11+
}
12+
13+
/// A declaration is something at the top-level of a module.
14+
///
15+
pub type Declaration {
16+
Function(
17+
name: String,
18+
parameters: List(String),
19+
body: Expression,
20+
publicity: Publicity,
21+
)
22+
Constant(name: String, value: Expression, publicity: Publicity)
23+
TopLevelExternal(javascript_code: String)
24+
}
25+
26+
/// Publicity determines whether a definition is exported from the module using
27+
/// the JS `export` keyword. Only top-level definitions can have a publicity since
28+
/// it doesn't make sense to export nested expressions.
29+
///
30+
pub type Publicity {
31+
Public
32+
Private
33+
}
34+
35+
/// Expressions represent every possible value that can be expressed in the
36+
/// language.
37+
///
38+
pub type Expression {
39+
Number(value: Float)
40+
String(value: String)
41+
Variable(name: String)
42+
List(values: List(Expression))
43+
Lambda(parameters: List(String), body: Expression)
44+
Call(function: Expression, arguments: List(Expression))
45+
Let(name: String, value: Expression, body: Expression)
46+
Binop(op: Binop, left: Expression, right: Expression)
47+
Unop(op: Unop, operand: Expression)
48+
Case(subject: Expression, clauses: List(CaseClause))
49+
External(javascript_code: String)
50+
}
51+
52+
/// Binary operators have two operands.
53+
///
54+
pub type Binop {
55+
// Math: +, -, *, /
56+
Add
57+
Sub
58+
Mul
59+
Div
60+
// Equality: ==, !=
61+
Eq
62+
Ne
63+
// Comparison: >, <, >=, <=
64+
Gt
65+
Lt
66+
GtEq
67+
LtEq
68+
// Logical: and, or
69+
And
70+
Or
71+
// Lists: :
72+
Cons
73+
// Expressions
74+
Semicolon
75+
}
76+
77+
/// Unary operators have one operand.
78+
///
79+
pub type Unop {
80+
// Math: -
81+
Neg
82+
// Logical: !
83+
Not
84+
}
85+
86+
/// A case clause consists of a pattern and its body.
87+
///
88+
pub type CaseClause {
89+
CaseClause(pattern: Pattern, body: Expression)
90+
}
91+
92+
/// Patterns are used to match against expressions.
93+
///
94+
pub type Pattern {
95+
ListPattern(list: List(Pattern), tail: Option(String))
96+
VariablePattern(name: String)
97+
NamedPattern(pattern: Pattern, name: String)
98+
IgnorePattern
99+
NumberPattern(value: Float)
100+
StringPattern(value: String)
101+
}

‎src/spark/error.gleam

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import nibble/lexer
2+
3+
// ---- TYPES ------------------------------------------------------------------
4+
5+
pub type Error {
6+
SyntaxError(message: String, hint: String, location: lexer.Span)
7+
}

0 commit comments

Comments
 (0)