halunke 0.3.1 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1cf23103f236d1d5c248fe1bf071db2e49873fe1
4
- data.tar.gz: 03a326bb35a35d4a6711b5e72ab11cd6f55fec40
3
+ metadata.gz: d378d2686f483584090e764b7d90eeb13b18614c
4
+ data.tar.gz: 7f280aa4dfe247d55b37b863a8766bf9113fb80f
5
5
  SHA512:
6
- metadata.gz: dba700ccf46564d88034913a3ff10168cbb6acb0d50abbcf9d3a0f32cdcdb12ccf594b877f0e20fce4d70f1f50df69095ffedfb1ccccefcb07d811c885d66bd8
7
- data.tar.gz: 7d641c828755558b4581fccdd536a82bf8ac4434c667c3731d74ad0404f64d31f602f9c66a00d346cc88b07c4a15719fdacd1676345c0d825c734ccf3eafbd4d
6
+ metadata.gz: 5d1721feb87183a3be4cb3efd2420cb1b4ca5263fcc525413c64ee1884420441761200227f200572a38f24d9b12e1b12f29ccfcafae05d7498cc3179a9a0dd41
7
+ data.tar.gz: ae52853223039380e48c35eb867f693a88b257f8510b9d79c67e4e0641d89df3489a3104ebffadc0bcdc5a9edcf588dae68f218e82c36a930f0d5e421bdb1340
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- halunke (0.3.1)
4
+ halunke (0.4.0)
5
5
  rack (~> 2.0.4)
6
6
 
7
7
  GEM
data/docs/_config.yml CHANGED
@@ -7,5 +7,7 @@ title: Halunke!
7
7
  description: >-
8
8
  Halunke is a dynamic, object-oriented language that has a simple grammar inspired by Smalltalk and Lisp
9
9
 
10
+ baseurl: "/halunke"
11
+
10
12
  # Build settings
11
13
  markdown: kramdown
@@ -10,41 +10,41 @@
10
10
  <body>
11
11
  <div class="container">
12
12
  <nav class="navbar navbar-expand-lg navbar-dark bg-dark">
13
- <a class="navbar-brand" href="#">Halunke!</a>
13
+ <a class="navbar-brand" href="/halunke">Halunke!</a>
14
14
  <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
15
15
  <span class="navbar-toggler-icon"></span>
16
16
  </button>
17
- <div class="collapse navbar-collapse">
17
+ <div class="collapse navbar-collapse" id="navbarNav">
18
18
  <ul class="navbar-nav">
19
19
  <li class="nav-item">
20
- <a class="nav-link" href="/">Intro</a>
20
+ <a class="nav-link" href="/halunke">Intro</a>
21
21
  </li>
22
22
  <li class="nav-item">
23
- <a class="nav-link" href="/number">Number</a>
23
+ <a class="nav-link" href="/halunke/number">Number</a>
24
24
  </li>
25
25
  <li class="nav-item">
26
- <a class="nav-link" href="/string">String</a>
26
+ <a class="nav-link" href="/halunke/string">String</a>
27
27
  </li>
28
28
  <li class="nav-item">
29
- <a class="nav-link" href="/array">Array</a>
29
+ <a class="nav-link" href="/halunke/array">Array</a>
30
30
  </li>
31
31
  <li class="nav-item">
32
- <a class="nav-link" href="/dictionary">Dictionary</a>
32
+ <a class="nav-link" href="/halunke/dictionary">Dictionary</a>
33
33
  </li>
34
34
  <li class="nav-item">
35
- <a class="nav-link" href="/true-false">True & False</a>
35
+ <a class="nav-link" href="/halunke/true-false">True & False</a>
36
36
  </li>
37
37
  <li class="nav-item">
38
- <a class="nav-link" href="/function">Function</a>
38
+ <a class="nav-link" href="/halunke/function">Function</a>
39
39
  </li>
40
40
  <li class="nav-item">
41
- <a class="nav-link" href="/class">Class</a>
41
+ <a class="nav-link" href="/halunke/class">Class</a>
42
42
  </li>
43
43
  <li class="nav-item">
44
- <a class="nav-link" href="/true-false">Stdio</a>
44
+ <a class="nav-link" href="/halunke/stdio">Stdio</a>
45
45
  </li>
46
46
  <li class="nav-item">
47
- <a class="nav-link" href="/true-false">Web</a>
47
+ <a class="nav-link" href="/halunke/web">Web</a>
48
48
  </li>
49
49
  </ul>
50
50
  </div>
@@ -57,5 +57,9 @@
57
57
  {{ content }}
58
58
  </main>
59
59
  </div>
60
+
61
+ <script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
62
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
63
+ <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>
60
64
  </body>
61
65
  </html>
data/docs/array.md ADDED
@@ -0,0 +1,65 @@
1
+ ---
2
+ title: Array
3
+ ---
4
+
5
+ In Halunke arrays are collections of objects. The objects do not
6
+ need to be of the same class. Arrays are sorted. They are
7
+ surrounded by square brackets. The items are separated by
8
+ whitespace.
9
+
10
+ ```
11
+ ["a" 1 "b"]
12
+ [
13
+ "a"
14
+ 5
15
+ ]
16
+ ```
17
+
18
+ It can answer to the following messages:
19
+
20
+ ## `=`
21
+
22
+ Compares to arrays. If they have the same length and each item from
23
+ the first array returns true on the `=` message for the according
24
+ item from the second list, it returns true. Otherwise, it returns
25
+ false. This can also be used to destructure an array.
26
+
27
+ **Example:**
28
+
29
+ ```
30
+ (["a" 1] = ["a" 1]) /* => true */
31
+
32
+ (['a 2] = [1 2]) /* => true */
33
+ /* a is now 2 */
34
+ ```
35
+
36
+ ## `map`
37
+
38
+ Calls the provided function for each element. Returns a new array of the same
39
+ length with the results of the function calls.
40
+
41
+ **Example:**
42
+
43
+ ```
44
+ ([0 1 2] map { |'x| (x + 1) }) /* => [1 2 3] */
45
+ ```
46
+
47
+ ## `to_s`
48
+
49
+ This returns a string to represent the array in output.
50
+
51
+ **Example:**
52
+
53
+ ```
54
+ ([0 1 2] to_s) /* => "0\n1\n2" */
55
+ ```
56
+
57
+ ## `inspect`
58
+
59
+ This returns a string to represent the array for debugging.
60
+
61
+ **Example:**
62
+
63
+ ```
64
+ ([0 1 2] inspect) /* => "[0 1 2]" */
65
+ ```
data/docs/class.md ADDED
@@ -0,0 +1,103 @@
1
+ ---
2
+ title: Class
3
+ ---
4
+
5
+ In Halunke, Classes are objects. They consist of a dictionary that
6
+ maps message names to functions. Objects are a wrapper around a
7
+ dictionary. The dictionary contains the attributes of the object.
8
+ The object knows its class, and when messages are send to the
9
+ object, it will look up the according function in its class and
10
+ call it.
11
+
12
+ Classes are created by sending a message to the Class object. One
13
+ of these messages is `new attributes methods`. Let's create a
14
+ class:
15
+
16
+ ```
17
+ (Class new 'Counter
18
+ attributes ["value"]
19
+ methods @[
20
+ "value" { |'self|
21
+ (self @ "value" else 0)
22
+ }
23
+ ]
24
+ )
25
+ ```
26
+
27
+ To create an instance of the class, we send the `new` message to
28
+ the class with a dictionary that represents the attributes:
29
+
30
+ ```
31
+ ('counter = (Counter new @["value" 0]))
32
+ ```
33
+
34
+ Now we can send the `value` message to our counter, and we will
35
+ receive 0:
36
+
37
+ ```
38
+ (counter value)
39
+ ```
40
+
41
+ In our class definition, we first gave an array of attributes. You
42
+ can imagine it as kind of whitelist for attributes: The attribute
43
+ dictionary you pass to new can only have keys that are on this
44
+ list. Now let's look at the function that is called when you send
45
+ the value message:
46
+
47
+ ```
48
+ { |'self| (self @ "value" else 0) }
49
+ ```
50
+
51
+ Every function that is used as a method receives the object itself
52
+ as its first argument. This can be used to send messages to the
53
+ object itself. Each object can receive the `@ else` message. This
54
+ is used to look up attributes in the dictionary. Our function
55
+ therefore returns the value attribute or 0, if it was not set.
56
+
57
+ Now let's add a method to increase the counter. Remember that objects
58
+ are immutable. So we need to return a new counter with the value
59
+ that is one higher than our current value:
60
+
61
+ ```
62
+ "increase" { |'self|
63
+ (Counter new @["value" ((self value) + 1)])
64
+ }
65
+ ```
66
+
67
+ We can use it like this:
68
+
69
+ ```
70
+ ('counter = (Counter new @["value" 0]))
71
+ ('increased_counter = (counter increase))
72
+ ```
73
+
74
+ The `'increased_counter` will return `1` as its value.
75
+
76
+ Now you might want to have a custom constructor that needs less typing and is
77
+ more expressive. You can do that by introducing a class method that calls the
78
+ `new` method. Class methods receive the class as the first parameter.
79
+
80
+ ```
81
+ (Class new 'Counter
82
+ attributes ["value"]
83
+ methods @[
84
+ "value" { |'self|
85
+ (self @ "value" else 0)
86
+ }
87
+ "increase" { |'self|
88
+ (Counter new @["value" ((self value) + 1)])
89
+ }
90
+ ]
91
+ class_methods @[
92
+ "from" { |'self 'value|
93
+ (self new @["value" value])
94
+ }
95
+ ]
96
+ )
97
+ ```
98
+
99
+ Now we can create a counter like this:
100
+
101
+ ```
102
+ ('counter = (Counter from 5))
103
+ ```
@@ -0,0 +1,48 @@
1
+ ---
2
+ title: Dictionary
3
+ ---
4
+
5
+ In Halunke, dictionaries are collections of objects that map values
6
+ to other values. The first entry is the key for the second entry,
7
+ the third for the fourth etc. (the number of elements is therefore
8
+ always even). Like in a real dictionary, you can then look them up
9
+ Like in a real dictionary, you can then look them up. They are
10
+ written in square brackets, prefixed with an `@`.
11
+
12
+ ```
13
+ @["a" 1 "b" 2]
14
+ ```
15
+
16
+ It can answer to the following message:
17
+
18
+ ## `@ else`
19
+
20
+ Looks up a value in the dictionary. If the key is not in the
21
+ dictionary, the fallback value is used.
22
+
23
+ **Example:**
24
+
25
+ ```
26
+ (@["a" 1 "b" 2] @ "a" else "Not Found") /* => 1 */
27
+ (@["a" 1 "b" 2] @ "c" else "Not Found") /* => "Not Found" */
28
+ ```
29
+
30
+ ## `to_s`
31
+
32
+ This returns a string to represent the dictionary in output.
33
+
34
+ **Example:**
35
+
36
+ ```
37
+ (@["a" 1 "b" 2] to_s) /* => "a 1\nb 2" */
38
+ ```
39
+
40
+ ## `inspect`
41
+
42
+ This returns a string to represent the dictionary for debugging.
43
+
44
+ **Example:**
45
+
46
+ ```
47
+ (@["a" 1 "b" 2] inspect) /* => "@[\"a\" 1 \"b\" 2]" */
48
+ ```
data/docs/function.md ADDED
@@ -0,0 +1,18 @@
1
+ ---
2
+ title: Function
3
+ ---
4
+
5
+ This is how you define a function:
6
+
7
+ ```
8
+ ('fn = { |'a 'b| (a + b) })
9
+ ```
10
+
11
+ This is a function that expects two arguments. Functions in Halunke are
12
+ Objects. If you want to invoke a function, you send them the `call` message
13
+ with an array with the arguments (in our case two):
14
+
15
+ ```
16
+ (fn call [1 2])
17
+ /* => 6 */
18
+ ```
data/docs/index.md CHANGED
@@ -57,12 +57,13 @@ works like this:
57
57
  This will return `"Spelunke!"`. The message we send here is `replace with` and
58
58
  the value is `["Ha" "Spe"]`.
59
59
 
60
- If you want to find out more about the types of objects in Halunke and the
61
- messages you can send to them, explore the navigation bar at the top. If you
62
- want to learn more about conditionals, check out the section about [True &
63
- False](/true-false). If you want to write your own functions, check out
64
- [Function](/function) and if you want to define your own classes, check out
65
- [Class](/class).
60
+ If you want to find out more about the types of objects in Halunke
61
+ and the messages you can send to them, explore the navigation bar
62
+ at the top. If you want to learn more about conditionals, check out
63
+ the section about [True & False](/halunke/true-false). If you want
64
+ to write your own functions, check out
65
+ [Function](/halunke/function) and if you want to define your own
66
+ classes, check out [Class](/halunke/class).
66
67
 
67
68
  If you want to store an object in a variable, you can do it like this:
68
69
 
@@ -75,3 +76,8 @@ Now you can send messages to `a` like `(a + 2)`. Why is there a `'` though? The
75
76
  with a value, and it will assign it. Be aware that you can't reassign. So if
76
77
  you assign something to a once, it will stay like this forever (within that
77
78
  scope). Reassigning will result in an error.
79
+
80
+ The values are also immutable. If you send a message to an object,
81
+ it will not change the object, but it will return an answer to you.
82
+
83
+ Comments are written between `/*` and `*/`. They can be multiline.
data/docs/number.md ADDED
@@ -0,0 +1,106 @@
1
+ ---
2
+ title: Number
3
+ ---
4
+
5
+ In Halunke all numbers are rational. You write them as decimal numbers:
6
+
7
+ ```
8
+ 2
9
+ -3
10
+ 2.12
11
+ ```
12
+
13
+ It can answer to the following messages:
14
+
15
+ ## `+`
16
+
17
+ This adds two numbers.
18
+
19
+ **Example:**
20
+
21
+ ```
22
+ (0.6 + 0.3) /* => 0.9 */
23
+ ```
24
+
25
+ ## `-`
26
+
27
+ This subtracts two numbers.
28
+
29
+ **Example:**
30
+
31
+ ```
32
+ (0.6 - 0.3) /* => 0.3 */
33
+ ```
34
+
35
+ ## `/`
36
+
37
+ This divides two numbers.
38
+
39
+ **Example:**
40
+
41
+ ```
42
+ (0.6 / 0.3) /* => 2 */
43
+ ```
44
+
45
+ ## `*`
46
+
47
+ This multiplies two numbers.
48
+
49
+ **Example:**
50
+
51
+ ```
52
+ (0.6 * 0.3) /* => 0.18 */
53
+ ```
54
+
55
+ ## `<`
56
+
57
+ This compares two numbers. It is true, if the first number is smaller than the
58
+ second number. Otherwise, it is false.
59
+
60
+ **Example:**
61
+
62
+ ```
63
+ (0.6 < 0.3) /* => false */
64
+ ```
65
+
66
+ ## `>`
67
+
68
+ This compares two numbers. It is true, if the first number is greater than the
69
+ second number. Otherwise, it is false.
70
+
71
+ **Example:**
72
+
73
+ ```
74
+ (0.6 > 0.3) /* => true */
75
+ ```
76
+
77
+ ## `=`
78
+
79
+ This compares two numbers. It is true, if the two numbers are equal. Otherwise,
80
+ it is false.
81
+
82
+ **Example:**
83
+
84
+ ```
85
+ (0.6 = 0.3) /* => false */
86
+ ```
87
+
88
+ ## `to_s`
89
+
90
+ This returns a string to represent the number in output.
91
+
92
+ **Example:**
93
+
94
+ ```
95
+ (0.6 to_s) /* => "0.6" */
96
+ ```
97
+
98
+ ## `inspect`
99
+
100
+ This returns a string to represent the number for debugging.
101
+
102
+ **Example:**
103
+
104
+ ```
105
+ (0.6 inspect) /* => "0.6" */
106
+ ```
data/docs/stdio.md ADDED
@@ -0,0 +1,62 @@
1
+ ---
2
+ title: Stdio
3
+ ---
4
+
5
+ The object `stdio` is available from everywhere. *This will change in the
6
+ future. Interacting with STDIO is IO and will be isolated.*
7
+
8
+ ## `puts`
9
+
10
+ Prints the object to stdout. To determine how to represent the object, it will
11
+ send the `to_s` message to the object, expecting a string.
12
+
13
+ **Example:**
14
+
15
+ ```
16
+ (stdio puts "Hello World")
17
+ (stdio puts 5.2)
18
+ (stdio puts @["a" 2 "b" 3])
19
+ (stdio puts ["a" "b"])
20
+ (stdio puts true)
21
+ (stdio puts false)
22
+ ```
23
+
24
+ This will output:
25
+
26
+ ```
27
+ Hello World
28
+ 5.2
29
+ a 2
30
+ b 3
31
+ a
32
+ b
33
+ true
34
+ false
35
+ ```
36
+
37
+ ## `p`
38
+
39
+ Prints the object to stdout for debugging. To determine how to represent the
40
+ object, it will send the `inspect` message to the object, expecting a string.
41
+
42
+ **Example:**
43
+
44
+ ```
45
+ (stdio p "Hello World")
46
+ (stdio p 5.2)
47
+ (stdio p @["a" 2 "b" 3])
48
+ (stdio p ["a" "b"])
49
+ (stdio p true)
50
+ (stdio p false)
51
+ ```
52
+
53
+ This will output:
54
+
55
+ ```
56
+ "Hello World"
57
+ 5.2
58
+ @["a" 2 "b" 3]
59
+ ["a" "b"]
60
+ true
61
+ false
62
+ ```
data/docs/string.md ADDED
@@ -0,0 +1,74 @@
1
+ ---
2
+ title: String
3
+ ---
4
+
5
+ In Halunke strings are used to represent all kinds of text
6
+ including single characters. They are surrounded by double quotes
7
+ (single quotes are not allowed).
8
+
9
+ ```
10
+ "Foo Bar"
11
+ ```
12
+
13
+ It can answer to the following messages:
14
+
15
+ ## `reverse`
16
+
17
+ Return a reversed version of the String.
18
+
19
+ **Example:**
20
+
21
+ ```
22
+ ("hello" reverse) /* => "olleh" */
23
+ ```
24
+
25
+ ## `replace with`
26
+
27
+ Replace all occurrences of the first string with the second string.
28
+
29
+ **Example:**
30
+
31
+ ```
32
+ ("ababab" replace "a" with "c") /* => "cbcbcb" */
33
+ ```
34
+
35
+ ## `=`
36
+
37
+ This compares two strings. It is true, if the two strings are equal. Otherwise,
38
+ it is false.
39
+
40
+ **Example:**
41
+
42
+ ```
43
+ ("aaa" = "aaa") /* => true */
44
+ ```
45
+
46
+ ## `+`
47
+
48
+ Concatenate two strings.
49
+
50
+ **Example:**
51
+
52
+ ```
53
+ ("aaa" + "bbb") /* => "aaabbb" */
54
+ ```
55
+
56
+ ## `to_s`
57
+
58
+ This returns the string itself.
59
+
60
+ **Example:**
61
+
62
+ ```
63
+ ("aaa" to_s) /* => "aaa" */
64
+ ```
65
+
66
+ ## `inspect`
67
+
68
+ This returns a string to represent the string in output. This is done by surrounding it with `"`
69
+
70
+ **Example:**
71
+
72
+ ```
73
+ ("aaa" inspect) /* => "\"aaa\"" */
74
+ ```
@@ -0,0 +1,68 @@
1
+ ---
2
+ title: True & False
3
+ ---
4
+
5
+ In Halunke `true` is an instance of the `True` class, and `false`
6
+ is an instance of the `False` class. They are used to realize
7
+ boolean operations (for example `and`) as well as for branching.
8
+ They answer to the same messages. So you could use it like this:
9
+
10
+ ```
11
+ ((5 > 3) then { "yes!" } else { "no!" })
12
+ /* Returns "yes!" */
13
+ ```
14
+
15
+ ## `and`
16
+
17
+ Returns true if both the receiver as well as the provided value are
18
+ true.
19
+
20
+ **Example:**
21
+
22
+ ```
23
+ ((5 > 3) and (2 < 1)) /* => false */
24
+ ```
25
+
26
+ ## `or`
27
+
28
+ Returns true if either the receiver or the provided value are true.
29
+
30
+ **Example:**
31
+
32
+ ```
33
+ ((5 > 3) or (2 < 1)) /* => true */
34
+ ```
35
+
36
+ ## `then else`
37
+
38
+ If the receiver is true, it will execute the first branch. If it is
39
+ false, it will return the second branch.
40
+
41
+ **Example:**
42
+
43
+ ```
44
+ (true then { "yes" } else { "no" }) /* => "yes" */
45
+ (false then { "yes" } else { "no" }) /* => "no" */
46
+ ```
47
+
48
+ ## `to_s`
49
+
50
+ This returns a string to represent true and false in output.
51
+
52
+ **Example:**
53
+
54
+ ```
55
+ (true to_s) /* => "true" */
56
+ (false to_s) /* => "false" */
57
+ ```
58
+
59
+ ## `inspect`
60
+
61
+ This returns a string to represent true and false for debugging.
62
+
63
+ **Example:**
64
+
65
+ ```
66
+ (true inspect) /* => "true" */
67
+ (false inspect) /* => "false" */
68
+ ```
data/docs/web.md ADDED
@@ -0,0 +1,32 @@
1
+ ---
2
+ title: Web
3
+ ---
4
+
5
+ The object `web` is available from everywhere. *This will change in the future.
6
+ Interacting with STDIO is IO and will be isolated.*
7
+
8
+ You can send the `run on` message to `web`. It expects the first object to be
9
+ your application (more on that later) and the second one the bind address and
10
+ port in the format: `0.0.0.0:3000`.
11
+
12
+ Your app needs to be an object that can receive the `call` message. It will be
13
+ called with the environment dictionary that represents the request. It expects
14
+ that your return an array that represents the response.
15
+
16
+ ## Environment Dictionary
17
+
18
+ The environment dictionary has the following keys:
19
+
20
+ * `request_method`: The request method in upper case (for example: `"GET"`)
21
+ * `path`: The path that was requested (for example: `"/the/path"`)
22
+ * `query`: The query part of the request (for example: `"foo=bar&beep=boop"`)
23
+
24
+ ## Response Array
25
+
26
+ The response array has three elements:
27
+
28
+ 1. The first element is the status code as a String (for example: `"200"`)
29
+ 2. The second element are the headers as a dictionary (for example: `@[
30
+ "Content-Type" "text/html" ]`)
31
+ 3. The third element is an array of strings that represent the body (for
32
+ example: `[ "<h1>Halunke!</h1>" ]`)
@@ -0,0 +1,22 @@
1
+ (Class new 'Counter
2
+ attributes ["value"]
3
+ methods @[
4
+ "value" { |'self|
5
+ (self @ "value" else 0)
6
+ }
7
+ "increase" { |'self|
8
+ (Counter new @["value" ((self value) + 1)])
9
+ }
10
+ ]
11
+ class_methods @[
12
+ "from" { |'self 'value|
13
+ (self new @["value" value])
14
+ }
15
+ ]
16
+ )
17
+
18
+ ('counter = (Counter from 0))
19
+ (stdio puts (counter value))
20
+
21
+ ('increased_counter = (counter increase))
22
+ (stdio puts (increased_counter value))
data/examples/hello.hal CHANGED
@@ -16,4 +16,4 @@
16
16
  )
17
17
 
18
18
  ('greeter = (Greeter for "World"))
19
- (stdout puts (greeter greet))
19
+ (stdio puts (greeter greet))
@@ -0,0 +1,13 @@
1
+ (stdio puts "Hello World")
2
+ (stdio puts 5.2)
3
+ (stdio puts @["a" 2 "b" 3])
4
+ (stdio puts ["a" "b"])
5
+ (stdio puts true)
6
+ (stdio puts false)
7
+
8
+ (stdio p "Hello World")
9
+ (stdio p 5.2)
10
+ (stdio p @["a" 2 "b" 3])
11
+ (stdio p ["a" "b"])
12
+ (stdio p true)
13
+ (stdio p false)
@@ -15,27 +15,29 @@ token BAR
15
15
  token START_COMMENT
16
16
  token END_COMMENT
17
17
 
18
+ options no_result_var
19
+
18
20
  rule
19
21
  Program:
20
- Expressions { result = val[0] }
22
+ Expressions { val[0] }
21
23
  ;
22
24
 
23
25
  Expressions:
24
- /* empty */ { result = Nodes.new([]) }
25
- | Expression Expressions { result = Nodes.new([val[0]].concat(val[1].nodes)) }
26
+ /* empty */ { Nodes.new([]) }
27
+ | Expression Expressions { Nodes.new([val[0]].concat(val[1].nodes)) }
26
28
  ;
27
29
 
28
30
  Expression:
29
- NUMBER { result = NumberNode.new(val[0]) }
30
- | STRING { result = StringNode.new(val[0]) }
31
- | BAREWORD { result = BarewordNode.new(val[0]) }
32
- | UNASSIGNED_BAREWORD { result = UnassignedNode.new(BarewordNode.new(val[0])) }
33
- | START_COMMENT Expressions END_COMMENT { result = Nodes.new([]) }
34
- | OPEN_CURLY Expressions CLOSE_CURLY { result = FunctionNode.new(ArrayNode.new([]), val[1]) }
35
- | OPEN_CURLY BAR Expressions BAR Expressions CLOSE_CURLY { result = FunctionNode.new(val[2].to_array, val[4]) }
36
- | OPEN_PAREN Expression Expressions CLOSE_PAREN { result = MessageSendNode.new(val[1], val[2].to_message) }
37
- | OPEN_BRACKET Expressions CLOSE_BRACKET { result = val[1].to_array }
38
- | OPEN_DICT_BRACKET Expressions CLOSE_BRACKET { result = val[1].to_dictionary }
31
+ NUMBER { NumberNode.new(val[0]) }
32
+ | STRING { StringNode.new(val[0]) }
33
+ | BAREWORD { BarewordNode.new(val[0]) }
34
+ | UNASSIGNED_BAREWORD { UnassignedNode.new(BarewordNode.new(val[0])) }
35
+ | START_COMMENT Expressions END_COMMENT { Nodes.new([]) }
36
+ | OPEN_CURLY Expressions CLOSE_CURLY { FunctionNode.new(ArrayNode.new([]), val[1]) }
37
+ | OPEN_CURLY BAR Expressions BAR Expressions CLOSE_CURLY { FunctionNode.new(val[2].to_array, val[4]) }
38
+ | OPEN_PAREN Expression Expressions CLOSE_PAREN { MessageSendNode.new(val[1], val[2].to_message) }
39
+ | OPEN_BRACKET Expressions CLOSE_BRACKET { val[1].to_array }
40
+ | OPEN_DICT_BRACKET Expressions CLOSE_BRACKET { val[1].to_dictionary }
39
41
  ;
40
42
  end
41
43
 
@@ -17,7 +17,7 @@ module Halunke
17
17
  @root_context["Array"] = Halunke::Runtime::HArray
18
18
  @root_context["Dictionary"] = Halunke::Runtime::HDictionary
19
19
  @root_context["UnassignedBareword"] = Halunke::Runtime::HUnassignedBareword
20
- @root_context["stdout"] = Halunke::Runtime::HStdout.create_instance
20
+ @root_context["stdio"] = Halunke::Runtime::HStdio.create_instance
21
21
  @root_context["web"] = Halunke::Runtime::HWeb.create_instance
22
22
 
23
23
  preludes.each do |prelude|
data/lib/halunke/lexer.rb CHANGED
@@ -99,10 +99,10 @@ self._lexer_trans_actions = [
99
99
  13, 0, 0, 0, 0, 0, 19, 21,
100
100
  0, 15, 29, 17, 31, 5, 9, 0,
101
101
  0, 33, 7, 0, 47, 47, 47, 45,
102
- 27, 39, 5, 37, 0, 5, 35, 0,
103
- 35, 25, 39, 23, 37, 0, 0, 0,
104
- 37, 43, 41, 39, 45, 39, 37, 35,
105
- 35, 39, 37, 37, 0
102
+ 27, 37, 5, 37, 0, 5, 35, 0,
103
+ 35, 25, 37, 23, 37, 0, 0, 0,
104
+ 37, 43, 41, 39, 45, 37, 37, 35,
105
+ 35, 37, 37, 37, 0
106
106
  ]
107
107
 
108
108
  class << self
@@ -128,8 +128,8 @@ class << self
128
128
  private :_lexer_eof_trans, :_lexer_eof_trans=
129
129
  end
130
130
  self._lexer_eof_trans = [
131
- 50, 51, 0, 58, 53, 58, 60, 57,
132
- 57, 58, 60, 60
131
+ 50, 51, 0, 52, 53, 60, 60, 57,
132
+ 57, 60, 60, 60
133
133
  ]
134
134
 
135
135
  class << self
data/lib/halunke/lexer.rl CHANGED
@@ -5,7 +5,7 @@
5
5
  number = ('+'|'-')?[0-9]+('.'[0-9]+)?;
6
6
  string = '"' [^"]* '"';
7
7
  unassigned_bareword = "'" [a-zA-Z_]+;
8
- bareword = [a-zA-Z_]+ | '+' | '-' | '<' | '>' | '=' | '@';
8
+ bareword = [a-zA-Z_]+ | '+' | '-' | '*' | '/' | '<' | '>' | '=' | '@';
9
9
  open_paren = '(';
10
10
  close_paren = ')';
11
11
  open_curly = '{';
@@ -13,7 +13,7 @@ require "halunke/nodes"
13
13
  module Halunke
14
14
  class Parser < Racc::Parser
15
15
 
16
- module_eval(<<'...end grammar.y/module_eval...', 'grammar.y', 48)
16
+ module_eval(<<'...end grammar.y/module_eval...', 'grammar.y', 50)
17
17
 
18
18
  def parse(code)
19
19
  @tokens = Lexer.new.tokenize(code)
@@ -124,7 +124,7 @@ racc_token_table = {
124
124
 
125
125
  racc_nt_base = 16
126
126
 
127
- racc_use_result_var = true
127
+ racc_use_result_var = false
128
128
 
129
129
  Racc_arg = [
130
130
  racc_action_table,
@@ -170,98 +170,85 @@ Racc_debug_parser = false
170
170
 
171
171
  # reduce 0 omitted
172
172
 
173
- module_eval(<<'.,.,', 'grammar.y', 19)
174
- def _reduce_1(val, _values, result)
175
- result = val[0]
176
- result
173
+ module_eval(<<'.,.,', 'grammar.y', 21)
174
+ def _reduce_1(val, _values)
175
+ val[0]
177
176
  end
178
177
  .,.,
179
178
 
180
- module_eval(<<'.,.,', 'grammar.y', 23)
181
- def _reduce_2(val, _values, result)
182
- result = Nodes.new([])
183
- result
179
+ module_eval(<<'.,.,', 'grammar.y', 25)
180
+ def _reduce_2(val, _values)
181
+ Nodes.new([])
184
182
  end
185
183
  .,.,
186
184
 
187
- module_eval(<<'.,.,', 'grammar.y', 24)
188
- def _reduce_3(val, _values, result)
189
- result = Nodes.new([val[0]].concat(val[1].nodes))
190
- result
191
- end
192
- .,.,
193
-
194
- module_eval(<<'.,.,', 'grammar.y', 28)
195
- def _reduce_4(val, _values, result)
196
- result = NumberNode.new(val[0])
197
- result
198
- end
199
- .,.,
200
-
201
- module_eval(<<'.,.,', 'grammar.y', 29)
202
- def _reduce_5(val, _values, result)
203
- result = StringNode.new(val[0])
204
- result
185
+ module_eval(<<'.,.,', 'grammar.y', 26)
186
+ def _reduce_3(val, _values)
187
+ Nodes.new([val[0]].concat(val[1].nodes))
205
188
  end
206
189
  .,.,
207
190
 
208
191
  module_eval(<<'.,.,', 'grammar.y', 30)
209
- def _reduce_6(val, _values, result)
210
- result = BarewordNode.new(val[0])
211
- result
192
+ def _reduce_4(val, _values)
193
+ NumberNode.new(val[0])
212
194
  end
213
195
  .,.,
214
196
 
215
197
  module_eval(<<'.,.,', 'grammar.y', 31)
216
- def _reduce_7(val, _values, result)
217
- result = UnassignedNode.new(BarewordNode.new(val[0]))
218
- result
198
+ def _reduce_5(val, _values)
199
+ StringNode.new(val[0])
219
200
  end
220
201
  .,.,
221
202
 
222
203
  module_eval(<<'.,.,', 'grammar.y', 32)
223
- def _reduce_8(val, _values, result)
224
- result = Nodes.new([])
225
- result
204
+ def _reduce_6(val, _values)
205
+ BarewordNode.new(val[0])
226
206
  end
227
207
  .,.,
228
208
 
229
209
  module_eval(<<'.,.,', 'grammar.y', 33)
230
- def _reduce_9(val, _values, result)
231
- result = FunctionNode.new(ArrayNode.new([]), val[1])
232
- result
210
+ def _reduce_7(val, _values)
211
+ UnassignedNode.new(BarewordNode.new(val[0]))
233
212
  end
234
213
  .,.,
235
214
 
236
215
  module_eval(<<'.,.,', 'grammar.y', 34)
237
- def _reduce_10(val, _values, result)
238
- result = FunctionNode.new(val[2].to_array, val[4])
239
- result
216
+ def _reduce_8(val, _values)
217
+ Nodes.new([])
240
218
  end
241
219
  .,.,
242
220
 
243
221
  module_eval(<<'.,.,', 'grammar.y', 35)
244
- def _reduce_11(val, _values, result)
245
- result = MessageSendNode.new(val[1], val[2].to_message)
246
- result
222
+ def _reduce_9(val, _values)
223
+ FunctionNode.new(ArrayNode.new([]), val[1])
247
224
  end
248
225
  .,.,
249
226
 
250
227
  module_eval(<<'.,.,', 'grammar.y', 36)
251
- def _reduce_12(val, _values, result)
252
- result = val[1].to_array
253
- result
228
+ def _reduce_10(val, _values)
229
+ FunctionNode.new(val[2].to_array, val[4])
254
230
  end
255
231
  .,.,
256
232
 
257
233
  module_eval(<<'.,.,', 'grammar.y', 37)
258
- def _reduce_13(val, _values, result)
259
- result = val[1].to_dictionary
260
- result
234
+ def _reduce_11(val, _values)
235
+ MessageSendNode.new(val[1], val[2].to_message)
236
+ end
237
+ .,.,
238
+
239
+ module_eval(<<'.,.,', 'grammar.y', 38)
240
+ def _reduce_12(val, _values)
241
+ val[1].to_array
242
+ end
243
+ .,.,
244
+
245
+ module_eval(<<'.,.,', 'grammar.y', 39)
246
+ def _reduce_13(val, _values)
247
+ val[1].to_dictionary
261
248
  end
262
249
  .,.,
263
250
 
264
- def _reduce_none(val, _values, result)
251
+ def _reduce_none(val, _values)
265
252
  val[0]
266
253
  end
267
254
 
@@ -7,5 +7,5 @@ require "halunke/runtime/hstring"
7
7
  require "halunke/runtime/harray"
8
8
  require "halunke/runtime/hdictionary"
9
9
  require "halunke/runtime/hunassigned_bareword"
10
- require "halunke/runtime/hstdout"
10
+ require "halunke/runtime/hstdio"
11
11
  require "halunke/runtime/hweb"
@@ -9,6 +9,9 @@
9
9
  "then else" { |'self 'true_branch 'false_branch|
10
10
  (false_branch call [])
11
11
  }
12
+ "to_s" { |'self 'other|
13
+ "false"
14
+ }
12
15
  "inspect" { |'self 'other|
13
16
  "false"
14
17
  }
@@ -4,10 +4,6 @@ module Halunke
4
4
  "Array",
5
5
  [],
6
6
  {
7
- "inspect" => HFunction.new([:self], lambda { |context|
8
- inspected_members = context["self"].ruby_value.map { |member| member.inspect(context) }
9
- HString.create_instance("[#{inspected_members.join(' ')}]")
10
- }),
11
7
  "=" => HFunction.new([:self, :other], lambda { |context|
12
8
  return context["false"] if context["self"].ruby_value.length != context["other"].ruby_value.length
13
9
 
@@ -21,6 +17,16 @@ module Halunke
21
17
  return HArray.create_instance(context["self"].ruby_value.map do |x|
22
18
  context["fn"].receive_message(context, "call", [HArray.create_instance([x])])
23
19
  end)
20
+ }),
21
+ "to_s" => HFunction.new([:self], lambda { |context|
22
+ inspected_members = context["self"].ruby_value.map do |member|
23
+ member.receive_message(context, "to_s", []).ruby_value
24
+ end
25
+ HString.create_instance("#{inspected_members.join("\n")}")
26
+ }),
27
+ "inspect" => HFunction.new([:self], lambda { |context|
28
+ inspected_members = context["self"].ruby_value.map { |member| member.inspect(context) }
29
+ HString.create_instance("[#{inspected_members.join(' ')}]")
24
30
  })
25
31
  },
26
32
  {},
@@ -4,6 +4,21 @@ module Halunke
4
4
  "Dictionary",
5
5
  [],
6
6
  {
7
+ "@ else" => HFunction.new([:self, :search, :fallback], lambda { |context|
8
+ result = context["self"].ruby_value.find do |key, _value|
9
+ key.receive_message(context, "=", [context["search"]]).inspect(context) == "true"
10
+ end
11
+ result ? result[1] : context["fallback"]
12
+ }),
13
+ "to_s" => HFunction.new([:self], lambda { |context|
14
+ x = []
15
+ context["self"].ruby_value.each_pair do |key, value|
16
+ key_s = key.receive_message(context, "to_s", [])
17
+ value_s = value.receive_message(context, "to_s", [])
18
+ x.push("#{key_s.ruby_value} #{value_s.ruby_value}")
19
+ end
20
+ HString.create_instance(x.join("\n"))
21
+ }),
7
22
  "inspect" => HFunction.new([:self], lambda { |context|
8
23
  x = []
9
24
  context["self"].ruby_value.each_pair do |key, value|
@@ -11,12 +26,6 @@ module Halunke
11
26
  x.push(value.inspect(context))
12
27
  end
13
28
  HString.create_instance("@[#{x.join(' ')}]")
14
- }),
15
- "@ else" => HFunction.new([:self, :search, :fallback], lambda { |context|
16
- result = context["self"].ruby_value.find do |key, _value|
17
- key.receive_message(context, "=", [context["search"]]).inspect(context) == "true"
18
- end
19
- result ? result[1] : context["fallback"]
20
29
  })
21
30
  },
22
31
  {},
@@ -7,6 +7,15 @@ module Halunke
7
7
  "+" => HFunction.new([:self, :other], lambda { |context|
8
8
  HNumber.create_instance(context["self"].ruby_value + context["other"].ruby_value)
9
9
  }),
10
+ "-" => HFunction.new([:self, :other], lambda { |context|
11
+ HNumber.create_instance(context["self"].ruby_value - context["other"].ruby_value)
12
+ }),
13
+ "/" => HFunction.new([:self, :other], lambda { |context|
14
+ HNumber.create_instance(context["self"].ruby_value / context["other"].ruby_value)
15
+ }),
16
+ "*" => HFunction.new([:self, :other], lambda { |context|
17
+ HNumber.create_instance(context["self"].ruby_value * context["other"].ruby_value)
18
+ }),
10
19
  "<" => HFunction.new([:self, :other], lambda { |context|
11
20
  if context["self"].ruby_value < context["other"].ruby_value
12
21
  context["true"]
@@ -28,10 +37,13 @@ module Halunke
28
37
  context["false"]
29
38
  end
30
39
  }),
31
- "inspect" => HFunction.new([:self], lambda { |context|
40
+ "to_s" => HFunction.new([:self], lambda { |context|
32
41
  float_value = context["self"].ruby_value.to_f
33
42
  float_value = float_value.to_i if float_value.to_i == float_value
34
43
  HString.create_instance(float_value.to_s)
44
+ }),
45
+ "inspect" => HFunction.new([:self], lambda { |context|
46
+ context["self"].receive_message(context, "to_s", [])
35
47
  })
36
48
  },
37
49
  {},
@@ -0,0 +1,22 @@
1
+ module Halunke
2
+ module Runtime
3
+ HStdio = HClass.new(
4
+ "Stdio",
5
+ [],
6
+ {
7
+ "puts" => HFunction.new([:self, :obj], lambda { |context|
8
+ str = context["obj"].receive_message(context, "to_s", [])
9
+ puts str.ruby_value
10
+ str
11
+ }),
12
+ "p" => HFunction.new([:self, :obj], lambda { |context|
13
+ str = context["obj"].receive_message(context, "inspect", [])
14
+ puts str.ruby_value
15
+ context["obj"]
16
+ })
17
+ },
18
+ {},
19
+ true
20
+ )
21
+ end
22
+ end
@@ -24,6 +24,9 @@ module Halunke
24
24
  "+" => HFunction.new([:self, :other], lambda { |context|
25
25
  HString.create_instance(context["self"].ruby_value + context["other"].ruby_value)
26
26
  }),
27
+ "to_s" => HFunction.new([:self], lambda { |context|
28
+ context["self"]
29
+ }),
27
30
  "inspect" => HFunction.new([:self], lambda { |context|
28
31
  HString.create_instance(context["self"].ruby_value.inspect)
29
32
  })
@@ -9,6 +9,9 @@
9
9
  "then else" { |'self 'true_branch 'false_branch|
10
10
  (true_branch call [])
11
11
  }
12
+ "to_s" { |'self 'other|
13
+ "true"
14
+ }
12
15
  "inspect" { |'self 'other|
13
16
  "true"
14
17
  }
@@ -1,3 +1,3 @@
1
1
  module Halunke
2
- VERSION = "0.3.1"
2
+ VERSION = "0.4.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: halunke
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.1
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Lucas Dohmen
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-02-10 00:00:00.000000000 Z
11
+ date: 2018-02-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack
@@ -104,8 +104,19 @@ files:
104
104
  - docs/Gemfile.lock
105
105
  - docs/_config.yml
106
106
  - docs/_layouts/default.html
107
+ - docs/array.md
108
+ - docs/class.md
109
+ - docs/dictionary.md
110
+ - docs/function.md
107
111
  - docs/index.md
112
+ - docs/number.md
113
+ - docs/stdio.md
114
+ - docs/string.md
115
+ - docs/true-false.md
116
+ - docs/web.md
117
+ - examples/counter.hal
108
118
  - examples/hello.hal
119
+ - examples/stdio.hal
109
120
  - examples/web.hal
110
121
  - exe/halunke
111
122
  - halunke.gemspec
@@ -125,7 +136,7 @@ files:
125
136
  - lib/halunke/runtime/hnative_object.rb
126
137
  - lib/halunke/runtime/hnumber.rb
127
138
  - lib/halunke/runtime/hobject.rb
128
- - lib/halunke/runtime/hstdout.rb
139
+ - lib/halunke/runtime/hstdio.rb
129
140
  - lib/halunke/runtime/hstring.rb
130
141
  - lib/halunke/runtime/hunassigned_bareword.rb
131
142
  - lib/halunke/runtime/hweb.rb
@@ -1,16 +0,0 @@
1
- module Halunke
2
- module Runtime
3
- HStdout = HClass.new(
4
- "Stdout",
5
- [],
6
- {
7
- "puts" => HFunction.new([:self, :str], lambda { |context|
8
- puts context["str"].ruby_value
9
- context["str"]
10
- })
11
- },
12
- {},
13
- true
14
- )
15
- end
16
- end