Skip to content

Commit 4bf94f4

Browse files
committed
✨ Many improvements
1 parent 4be837b commit 4bf94f4

14 files changed

+1187
-397
lines changed

gleam.toml

+4-2
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,13 @@ version = "1.0.0"
1010
# links = [{ title = "Website", href = "https://gleam.run" }]
1111
#
1212
# For a full reference of all the available options, you can have a look at
13-
# https://gleam.run/writing-gleam/gleam-toml/.
13+
# https://gleam.run/writing-gleam/gleam-toml/.
1414

1515
[dependencies]
1616
gleam_stdlib = "~> 0.34 or ~> 1.0"
17-
nibble = "~> 1.1"
17+
chomp = { path = "../chomp-nibble" }
18+
gleam_community_ansi = ">= 1.4.0 and < 2.0.0"
19+
hug = "~> 1.0"
1820

1921
[dev-dependencies]
2022
gleeunit = "~> 1.0"

grammar.md

+41-31
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
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.
22

3-
> todo: atoms, atom patterns, of operator, named patterns, module imports, dot notation for modules, backpassing
4-
53
```ebnf
64
(* Module *)
75
8-
module = declaration* -> Module ;
6+
module = {import} {declaration} -> Module ;
7+
8+
import = "import" MODULE {"/" MODULE} ["as" MODULE] ;
99
1010
(* Declarations *)
1111
@@ -22,48 +22,47 @@ constant = "const" ["pub"] IDENT "=" expression ;
2222
(* Expressions *)
2323
2424
expression
25-
= ops
26-
| lambda -> Lambda
27-
| let -> Let
28-
| case -> Case
25+
= operator
26+
| lambda -> Lambda
27+
| backpass -> Call (* backpassing *)
28+
| let -> Let
29+
| case -> Case
2930
;
3031
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-
;
32+
operator = call ?pratt ...? ; (* see operator fn in parse.gleam *)
4833
4934
(* calls have the highest precedence but are not in the pratt parser since they aren't really operators *)
50-
call = primary {"(" [comma_sep<expression>] ")"} ;
35+
call = primary {"(" [comma_sep<expression>] ")" | "." IDENT} ;
5136
5237
primary
5338
=
5439
| NUMBER -> Number
5540
| STRING -> String
5641
| IDENT -> Variable
42+
| atom -> Atom
43+
| MODULE "." IDENT -> ModuleAccess
5744
| list -> List
45+
| record -> Record
5846
| external -> External
5947
| "(" expression ")"
6048
;
6149
50+
atom
51+
= ATOM
52+
| ATOM "(" [comma_sep<expression>] ")"
53+
| ATOM record
54+
;
55+
6256
list = "[" [comma_sep<expression>] "]" ;
6357
58+
record = "{" (".." expression "," comma_sep<record_field> | [comma_sep<record_fields>]) "}" ;
59+
record_field = IDENT [":" expression] ;
60+
6461
external = "external" STRING ;
6562
66-
lambda = "\\" comma_sep<IDENT> "->" expression ;
63+
lambda = "\\" [comma_sep<IDENT>] "->" expression ;
64+
65+
backpass = "\\" [comma_sep<IDENT>] "<-" expression expression ;
6766
6867
let = "let" Ident "=" expression "in" expression ;
6968
@@ -72,18 +71,29 @@ case = "case" expression ("|" pattern "=" expression)+ ;
7271
(* Patterns *)
7372
7473
pattern
75-
= list_pattern -> ListPattern
76-
| "_" -> IgnorePattern
77-
| IDENT -> VariablePattern
78-
| NUMBER -> NumberPattern
79-
| STRING -> StringPattern
74+
= list_pattern -> ListPattern
75+
| record_pattern -> RecordPattern
76+
| "_" -> IgnorePattern
77+
| IDENT -> VariablePattern
78+
| NUMBER -> NumberPattern
79+
| STRING -> StringPattern
80+
| atom_pattern -> AtomPattern
81+
| pattern "as" IDENT -> NamedPattern
8082
;
8183
8284
list_pattern
8385
= "[" [comma_sep<pattern>] "]"
8486
| "[" comma_sep<pattern> [":" IDENT] "]"
8587
;
8688
89+
record_pattern = "{" {comma_sep<IDENT [":" pattern]>} "}" ;
90+
91+
atom_pattern
92+
= ATOM
93+
| ATOM "(" [comma_sep<pattern>] ")"
94+
| ATOM record_pattern
95+
;
96+
8797
(* Helpers *)
8898
8999
comma_sep<rule> = rule {"," rule} ;

ideas.txt

+58
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import Spark/IO
2+
import Spark/Result
3+
4+
def pub main = with IO.then {
5+
IO.println("Hello, world!")
6+
let name = IO.readln()
7+
IO.println("Hey there, " + name + "!")
8+
}
9+
10+
def pub main = do IO.then {
11+
let contents = IO.read("./test.txt")
12+
IO.write("./test.txt", contents + " appended!")
13+
IO.println("yay")
14+
}
15+
16+
def println\text =
17+
@IO {
18+
perform: \ -> external "
19+
console.log(text);
20+
return $.nil();
21+
"
22+
}
23+
24+
def then\action, f =
25+
@IO {
26+
perform: \ -> f(action.perform()).perform()
27+
}
28+
29+
def test =
30+
\_ <- println("Hello!") |> then
31+
println("Goodbye, now.")
32+
33+
def external = with Chomp.do {
34+
Chomp.token(@external)
35+
let code = string()
36+
return(@external(code))
37+
}
38+
39+
def string =
40+
Chomp.take_map(\tok ->
41+
case tok
42+
| @string of x = @some of x
43+
| _ = @none
44+
)
45+
46+
def pub try\result, then =
47+
case result
48+
| @ok of payload = then(payload)
49+
| @ok = then()
50+
| any @error as error = error
51+
52+
def write\path, contents = # ...
53+
def read\path = # ...
54+
55+
def pub main =
56+
\contents <- read("./test.txt") |> try
57+
\<- write("./test.txt", contents + " appended!") |> try
58+
io.println("I did it!!")

manifest.toml

+12-10
Original file line numberDiff line numberDiff line change
@@ -3,29 +3,31 @@
33

44
packages = [
55
{ 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" },
6+
{ name = "birdie", version = "1.1.2", build_tools = ["gleam"], requirements = ["argv", "filepath", "glance", "gleam_community_ansi", "gleam_erlang", "gleam_stdlib", "justin", "rank", "simplifile", "trie_again"], otp_app = "birdie", source = "hex", outer_checksum = "F9666AEB5F6EDFAE6ADF9DFBF10EF96A4EDBDDB84B854C29B9A3F615A6436311" },
7+
{ name = "chomp", version = "1.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], source = "local", path = "../chomp-nibble" },
8+
{ name = "filepath", version = "1.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "filepath", source = "hex", outer_checksum = "EFB6FF65C98B2A16378ABC3EE2B14124168C0CE5201553DE652E2644DCFDB594" },
99
{ 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" },
10+
{ name = "glance", version = "0.9.0", build_tools = ["gleam"], requirements = ["gleam_stdlib", "glexer"], otp_app = "glance", source = "hex", outer_checksum = "4866132929EAA47649FBBDBD7C4FDBEB7E30938AA34561E4486640D8ABDE3C88" },
1111
{ 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" },
1212
{ 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" },
1313
{ name = "gleam_erlang", version = "0.25.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_erlang", source = "hex", outer_checksum = "054D571A7092D2A9727B3E5D183B7507DAB0DA41556EC9133606F09C15497373" },
1414
{ 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" },
15+
{ name = "gleam_stdlib", version = "0.34.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "1FB8454D2991E9B4C0C804544D8A9AD0F6184725E20D63C3155F0AEB4230B016" },
16+
{ name = "gleeunit", version = "1.1.2", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "72CDC3D3F719478F26C4E2C5FED3E657AC81EC14A47D2D2DEBB8693CA3220C3B" },
1717
{ name = "glexer", version = "0.7.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "glexer", source = "hex", outer_checksum = "4484942A465482A0A100936E1E5F12314DB4B5AC0D87575A7B9E9062090B96BE" },
18+
{ name = "hug", version = "1.0.0", build_tools = ["gleam"], requirements = ["gleam_community_ansi", "gleam_community_colour", "gleam_stdlib"], otp_app = "hug", source = "hex", outer_checksum = "D7D8C4F5A3093FB0B6A0228288D94E95966AADC5500133F9E983BA4634E92CC8" },
1819
{ 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" },
20+
{ name = "pprint", version = "1.0.1", build_tools = ["gleam"], requirements = ["glam", "gleam_stdlib"], otp_app = "pprint", source = "hex", outer_checksum = "86E63F89D5EECAE9D46640EBE59100302EF94C3A551D94787EEDD03A3A74EB8C" },
2121
{ 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" },
22+
{ name = "simplifile", version = "1.7.0", build_tools = ["gleam"], requirements = ["filepath", "gleam_stdlib"], otp_app = "simplifile", source = "hex", outer_checksum = "1D5DFA3A2F9319EC85825F6ED88B8E449F381B0D55A62F5E61424E748E7DDEB0" },
2323
{ name = "thoas", version = "0.4.1", build_tools = ["rebar3"], requirements = [], otp_app = "thoas", source = "hex", outer_checksum = "4918D50026C073C4AB1388437132C77A6F6F7C8AC43C60C13758CC0ADCE2134E" },
2424
{ name = "trie_again", version = "1.1.2", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "trie_again", source = "hex", outer_checksum = "5B19176F52B1BD98831B57FDC97BD1F88C8A403D6D8C63471407E78598E27184" },
2525
]
2626

2727
[requirements]
28+
chomp = { path = "../chomp-nibble" }
29+
gleam_community_ansi = { version = ">= 1.4.0 and < 2.0.0" }
2830
gleam_stdlib = { version = "~> 0.34 or ~> 1.0" }
2931
gleeunit = { version = "~> 1.0" }
30-
nibble = { version = "~> 1.1" }
32+
hug = { version = "~> 1.0" }
3133
pprint = { version = "~> 1.0" }

src/spark.gleam

+76-14
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,86 @@
11
import gleam/io
2-
import spark/lexer
3-
import spark/parser
2+
import gleam/result
43
import pprint
4+
import spark/error
5+
import spark/lex
6+
import spark/parse
57

68
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]
9+
let source =
10+
"
11+
import Spark/IO
1112
12-
external \"import fs from 'node:fs';\"
13+
external \"let $id = 0;\"
1314
14-
const foo = external \"blah blah\"
15+
def pub fresh_id =
16+
external \"return $id++\"
1517
16-
def add\\a, b =
17-
a + b
18+
def pub map\\over, fn =
19+
case over
20+
| [] as list = list
21+
| [x : xs] = fn(x) : map(xs, fn)
1822
19-
const test = blah(1, (), 2)")
23+
const squares = map([1, 2, 3], \\x -> x * x)
2024
21-
parser.parse(tokens)
22-
|> pprint.debug
23-
io.println("Hello from spark!")
25+
const foo =
26+
\\sum <- add_with_cb(5, 6)
27+
sum * (2 + 3 * external \"return 5\")
28+
29+
const bar =
30+
[1, 2, 3]
31+
|> baz
32+
|> map(\\x -> x * x)
33+
34+
def pub main =
35+
IO.println(\"Hello, world!\") ;
36+
37+
\"Isn't this language nice?\"
38+
|> IO.println ;
39+
40+
2 * 3
41+
42+
const dsf =
43+
case { x: 3, y: 5, z: 5 }
44+
| { x, y, z } = x + y + z
45+
| { x, y } = x + y
46+
47+
def println\\text =
48+
@IO {
49+
perform: \\ -> external \"
50+
console.log(text);
51+
return $.nil();
52+
\"
53+
}
54+
55+
def then\\action, f =
56+
@IO {
57+
perform: \\ -> action |> perform |> f |> perform
58+
}
59+
60+
def perform\\action =
61+
case action
62+
| @IO { perform } = perform()
63+
64+
def test =
65+
\\_ <- println(\"Hello!\") |> then
66+
println(\"Goodbye, now.\")
67+
68+
const me = @(\"Joe\", 30)
69+
"
70+
71+
let result = {
72+
use tokens <- result.try(lex.lex(source))
73+
use ast <- result.try(parse.parse(tokens))
74+
Ok(ast)
75+
}
76+
77+
case result {
78+
Ok(ast) -> {
79+
pprint.debug(ast)
80+
Nil
81+
}
82+
Error(e) ->
83+
error.to_string(e, source, "file.spark")
84+
|> io.println_error
85+
}
2486
}

0 commit comments

Comments
 (0)