dagon 0.1.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.
Files changed (80) hide show
  1. data/.gitignore +2 -0
  2. data/.rspec +1 -0
  3. data/Gemfile +4 -0
  4. data/LICENSE +22 -0
  5. data/README.md +86 -0
  6. data/Rakefile +40 -0
  7. data/bin/dagon +44 -0
  8. data/bin/dspec +35 -0
  9. data/bin/idg +15 -0
  10. data/bin/idgr +16 -0
  11. data/build/parser.rb +1015 -0
  12. data/build/scanner.rb +686 -0
  13. data/core/array.rb +64 -0
  14. data/core/block.rb +38 -0
  15. data/core/class.rb +91 -0
  16. data/core/false.rb +38 -0
  17. data/core/float.rb +93 -0
  18. data/core/frame.rb +24 -0
  19. data/core/hash.rb +51 -0
  20. data/core/integer.rb +98 -0
  21. data/core/object.rb +50 -0
  22. data/core/string.rb +57 -0
  23. data/core/true.rb +37 -0
  24. data/core/vm.rb +125 -0
  25. data/core/void.rb +37 -0
  26. data/dagon.gemspec +19 -0
  27. data/dagon.vim +45 -0
  28. data/dagon/ast/array_node.rb +17 -0
  29. data/dagon/ast/assignment_node.rb +21 -0
  30. data/dagon/ast/block_node.rb +19 -0
  31. data/dagon/ast/class_definition_node.rb +24 -0
  32. data/dagon/ast/constant_ref_node.rb +15 -0
  33. data/dagon/ast/frame.rb +23 -0
  34. data/dagon/ast/function_call_node.rb +33 -0
  35. data/dagon/ast/function_definition_node.rb +15 -0
  36. data/dagon/ast/function_node.rb +23 -0
  37. data/dagon/ast/hash_node.rb +16 -0
  38. data/dagon/ast/if_node.rb +20 -0
  39. data/dagon/ast/instance_init_node.rb +28 -0
  40. data/dagon/ast/instance_var_ref_node.rb +21 -0
  41. data/dagon/ast/literal_node.rb +23 -0
  42. data/dagon/ast/node.rb +22 -0
  43. data/dagon/ast/root_node.rb +19 -0
  44. data/dagon/ast/string_node.rb +16 -0
  45. data/dagon/ast/unary_function_call_node.rb +17 -0
  46. data/dagon/ast/var_ref_node.rb +19 -0
  47. data/dagon/ast/while_node.rb +17 -0
  48. data/dagon/parser.y +151 -0
  49. data/dagon/scanner.rl +143 -0
  50. data/examples/assert.dg +8 -0
  51. data/examples/assignment.dg +2 -0
  52. data/examples/block.dg +8 -0
  53. data/examples/class.dg +6 -0
  54. data/examples/conditional.dg +3 -0
  55. data/examples/conditions.dg +6 -0
  56. data/examples/equality.dg +6 -0
  57. data/examples/error.dg +1 -0
  58. data/examples/eval.dg +1 -0
  59. data/examples/fibonacci.dg +15 -0
  60. data/examples/greeter.dg +6 -0
  61. data/examples/input.dg +3 -0
  62. data/examples/instance_variables.dg +11 -0
  63. data/examples/iterate.dg +2 -0
  64. data/examples/method_call.dg +9 -0
  65. data/examples/method_definition.dg +4 -0
  66. data/examples/operators.dg +6 -0
  67. data/examples/output.dg +1 -0
  68. data/examples/require.dg +1 -0
  69. data/spec/array_spec.dg +26 -0
  70. data/spec/assertions.dg +11 -0
  71. data/spec/boolean_spec.dg +48 -0
  72. data/spec/dspec.dg +16 -0
  73. data/spec/float_spec.dg +15 -0
  74. data/spec/hash_spec.dg +6 -0
  75. data/spec/number_spec.dg +18 -0
  76. data/spec/return_spec.dg +12 -0
  77. data/spec/string_spec.dg +18 -0
  78. data/spec/void_spec.dg +9 -0
  79. data/spec/while_spec.dg +7 -0
  80. metadata +180 -0
@@ -0,0 +1,143 @@
1
+ # vim: set syntax=ruby:
2
+
3
+ =begin
4
+ %%{
5
+ machine new_parser;
6
+ newline = "\r"? "\n" | "\r";
7
+ newlines = newline+;
8
+ keyword = 'if' | 'elseif' | 'else' | 'while' | 'true' | 'false' | 'void';
9
+ string = '"' ( [^"\\] | /\\./ )* '"';
10
+ comment = '#' (any - newline)* newline;
11
+ constant = upper (alnum | '-')*;
12
+ identifier = '-'? lower (lower | digit | '-')*;
13
+ assignment = ': ';
14
+ arrow = '->';
15
+ colon = ':';
16
+ operator = ' + ' | ' - ' | ' * ' | ' / ' | ' = ' | ' != ' | ' < ' | ' > ' | ' <= ' | ' >= ' | ' && ' | ' || ' | ' ^ ';
17
+ exponent = ' ** ';
18
+ lparen = '(';
19
+ rparen = ')';
20
+ lbracket = '[';
21
+ rbracket = ']';
22
+ lbrace = '{';
23
+ rbrace = '}';
24
+ comma = ', ';
25
+ bang = '!';
26
+ dot = '.';
27
+ float = digit+ '.' digit+;
28
+ integer = '-'? digit+;
29
+ indent = " ";
30
+ at = "@";
31
+
32
+ main := |*
33
+ newlines { @last_indent_count = @indent_count; @indent_count = 0; @line += data[ts...te].lines.count; @column = 0; @check_indents = true };
34
+ comment { handle_indents };
35
+ keyword => { emit(data[ts...te].upcase.to_sym, data, ts, te) };
36
+ string => { emit_string(data, ts, te) };
37
+ constant => { emit(:CONSTANT, data, ts, te) };
38
+ identifier => { emit(:IDENTIFIER, data, ts, te) };
39
+ assignment => { emit(:ASSIGNMENT, data, ts, te-1) };
40
+ arrow => { emit(:ARROW, data, ts, te) };
41
+ colon => { emit(':', data, ts, te) };
42
+ float => { emit(:FLOAT, data, ts, te) };
43
+ integer => { emit(:INTEGER, data, ts, te) };
44
+ indent => { @indent_count += 1; };
45
+ lparen => { emit(:LPAREN, data, ts, te) };
46
+ rparen => { emit(:RPAREN, data, ts, te) };
47
+ lbrace => { emit(:LBRACE, data, ts, te) };
48
+ rbrace => { emit(:RBRACE, data, ts, te) };
49
+ lbracket => { emit(:LBRACKET, data, ts, te) };
50
+ rbracket => { emit(:RBRACKET, data, ts, te) };
51
+ dot => { emit(:DOT, data, ts, te) };
52
+ bang => { emit('!', data, ts, te) };
53
+ at => { emit('@', data, ts, te) };
54
+ operator => { emit(data[(ts+1)...(te-1)], data, ts + 1, te - 1) };
55
+ exponent => { emit(:EXPONENT, data, ts + 1, te - 1) };
56
+ comma => { emit(:COMMA, data, ts, te) };
57
+ space;
58
+
59
+ any => { problem(data, ts, te) };
60
+ *|;
61
+ }%%
62
+ =end
63
+
64
+ module Dagon
65
+ class Token < Struct.new(:data, :line); end
66
+ class Scanner
67
+
68
+ def initialize
69
+ %% write data;
70
+ # % fix syntax highlighting
71
+ end
72
+
73
+ def emit(name, data, start_char, end_char)
74
+ handle_indents
75
+ if @tokens.last && @tokens.last[0] == :IDENTIFIER && name == :LBRACKET
76
+ @tokens << ['[', Token.new(data[start_char...end_char], @line)]
77
+ else
78
+ @tokens << [name, Token.new(data[start_char...end_char], @line)]
79
+ end
80
+ @column += end_char - start_char
81
+ end
82
+
83
+ def emit_string(data, start_char, end_char)
84
+ handle_indents
85
+ str = data[(start_char+1)...(end_char-1)]
86
+ str = eval("\"#{str}\"") # ...
87
+ @tokens << [:STRING, Token.new(str, @line)]
88
+ @column += end_char - start_char
89
+ end
90
+
91
+ def handle_indents
92
+ if @check_indents
93
+ @check_indents = false
94
+ if @indent_count > @last_indent_count
95
+ (@indent_count - @last_indent_count).times do
96
+ @tokens << [:INDENT, Token.new(" ", @line)]
97
+ end
98
+ elsif @indent_count < @last_indent_count
99
+ (@last_indent_count - @indent_count).times do
100
+ @tokens << [:DEDENT, Token.new(" ", @line)]
101
+ end
102
+ @last_indent_count = @indent_count
103
+ end
104
+ end
105
+ end
106
+
107
+ def problem(data, ts, te)
108
+ puts "Unexpected \"#{data[ts...te]}\" on line #{@line}\n" +
109
+ "#{@line}: #{@lines[@line-1]}"
110
+ exit(1)
111
+ end
112
+
113
+ def self.tokenize data, filename
114
+ new.tokenize(data, filename)
115
+ end
116
+
117
+ def reset
118
+ @line = 1
119
+ @column = 0
120
+ @tokens = []
121
+ @indent_count = 0
122
+ @last_indent_count = 0
123
+ @check_indents = true
124
+ end
125
+
126
+ def tokenize(data, filename)
127
+ @filename = filename
128
+ @data = data
129
+ @lines = data.lines.to_a
130
+ reset
131
+ %% write init;
132
+ eof = data.length
133
+ %% write exec;
134
+ @check_indents = true
135
+ if @indent_count != 0
136
+ @last_indent_count = @indent_count
137
+ @indent_count = 0
138
+ end
139
+ handle_indents
140
+ @tokens
141
+ end
142
+ end
143
+ end
@@ -0,0 +1,8 @@
1
+ assert(value):
2
+ if value
3
+ true
4
+ else
5
+ puts("Failed assertion.")
6
+
7
+ assert(true)
8
+ assert(false)
@@ -0,0 +1,2 @@
1
+ x: 1
2
+ puts(x)
@@ -0,0 +1,8 @@
1
+ indent-block:
2
+ puts("indented")
3
+
4
+
5
+ inline-block: { puts("inline") }
6
+
7
+ indent-block()
8
+ inline-block()
@@ -0,0 +1,6 @@
1
+ MyClass:
2
+ x: 5
3
+
4
+ s: String("Hello")
5
+
6
+ puts(s)
@@ -0,0 +1,3 @@
1
+ if true
2
+ puts("Hello wombat")
3
+
@@ -0,0 +1,6 @@
1
+ if false
2
+ puts(1)
3
+ elseif true
4
+ puts("fuck yeah")
5
+ else
6
+ puts("huh?")
@@ -0,0 +1,6 @@
1
+ if 1 = 1
2
+ puts("numbers")
3
+ if "foo" = "foo"
4
+ puts("strings")
5
+ if "foo" = "bar"
6
+ puts("Should not see this")
@@ -0,0 +1 @@
1
+ 1 + 2()
@@ -0,0 +1 @@
1
+ eval("puts(\"Hello wombat\")")
@@ -0,0 +1,15 @@
1
+ current: 3
2
+ fibonacci-imperative(n):
3
+ current: 0
4
+ next: 1
5
+
6
+ n.times ->
7
+ temp: next
8
+ next: next + current
9
+ current: temp
10
+
11
+ current
12
+
13
+
14
+ puts(fibonacci-imperative(10))
15
+ puts(current)
@@ -0,0 +1,6 @@
1
+ Greeter:
2
+ greet(name):
3
+ puts("Hello " + name)
4
+
5
+ greeter: Greeter()
6
+ greeter.greet("wombat")
@@ -0,0 +1,3 @@
1
+ puts("What is your name")
2
+ name: gets
3
+ puts("Hello " + name)
@@ -0,0 +1,11 @@
1
+ Foo:
2
+ init:
3
+ @wombat: "wombat"
4
+ to-s:
5
+ @wombat
6
+ to-foo:
7
+ @foo
8
+
9
+ foo: Foo()
10
+ puts(foo.to-s())
11
+ puts(foo.to-foo())
@@ -0,0 +1,2 @@
1
+ [1, 2, 3, 4, 5].each ->(i)
2
+ puts(i)
@@ -0,0 +1,9 @@
1
+ tell(name, message):
2
+ print("Hey, ")
3
+ print(name)
4
+ print(": ")
5
+ print(message)
6
+ puts("!")
7
+
8
+ tell("Caleb", "you're a hero")
9
+ tell(message: "what's up", name: "Dagon")
@@ -0,0 +1,4 @@
1
+ foo(bar):
2
+ puts(bar)
3
+ foo("banana")
4
+
@@ -0,0 +1,6 @@
1
+ puts(5 + 3)
2
+ puts(12 - 6)
3
+ puts(7 * 1)
4
+ puts(10 / 2)
5
+ puts(3 ** 1)
6
+ puts(4 - 2 * 2)
@@ -0,0 +1 @@
1
+ puts("Hello world")
@@ -0,0 +1 @@
1
+ require("greeter")
@@ -0,0 +1,26 @@
1
+ require("assertions")
2
+ require("dspec")
3
+
4
+ describe("Array") ->
5
+ it("can be accessed") ->
6
+ array: [1, 2, 3]
7
+ assert-equal(array[0], 1)
8
+
9
+ it("can add arrays together") ->
10
+ assert-equal([1, 2, 3] + [4], [1, 2, 3, 4])
11
+
12
+ it("can subtract arrays from each other") ->
13
+ assert-equal([1, 1, 2, 2, 3, 3, 4, 5] - [1, 2, 4], [3, 3, 5])
14
+
15
+ it("can compact") ->
16
+ assert-equal([1, void, 2].compact, [1, 2])
17
+
18
+ it("knows it's length") ->
19
+ assert-equal([1, 2, 3].length, 3)
20
+
21
+ it("can iterate over the array") ->
22
+ array: [1, 2, 3]
23
+ x: 0
24
+ array.each ->(i)
25
+ x: x + i
26
+ assert-equal(x, 6)
@@ -0,0 +1,11 @@
1
+ -assert(expression):
2
+ if expression
3
+ true
4
+ else
5
+ false
6
+
7
+ assert-equal(lhs, rhs):
8
+ -assert(lhs = rhs)
9
+
10
+ assert-not-equal(lhs, rhs):
11
+ -assert(lhs != rhs)
@@ -0,0 +1,48 @@
1
+ describe("Booleans") ->
2
+ it("!true = false") ->
3
+ assert-equal(!true, false)
4
+
5
+ it("!false = true") ->
6
+ assert-equal(!false, true)
7
+
8
+ it("!!false = false") ->
9
+ assert-equal(!!false, false)
10
+
11
+ it("!!true = true") ->
12
+ assert-equal(!!true, true)
13
+
14
+ it("true && true = true") ->
15
+ assert-equal(true && true, true)
16
+
17
+ it("true && false = false") ->
18
+ assert-equal(true && false, false)
19
+
20
+ it("false && true = false") ->
21
+ assert-equal(false && true, false)
22
+
23
+ it("false && false = false") ->
24
+ assert-equal(false && false, false)
25
+
26
+ it("true || true = true") ->
27
+ assert-equal(true || true, true)
28
+
29
+ it("true || false = true") ->
30
+ assert-equal(true || false, true)
31
+
32
+ it("false || true = true") ->
33
+ assert-equal(false || true, true)
34
+
35
+ it("false || false = false") ->
36
+ assert-equal(false || false, false)
37
+
38
+ it("true ^ true = false") ->
39
+ assert-equal(true ^ true, false)
40
+
41
+ it("true ^ false = true") ->
42
+ assert-equal(true ^ false, true)
43
+
44
+ it("false ^ true = true") ->
45
+ assert-equal(false ^ true, true)
46
+
47
+ it("false ^ false = false") ->
48
+ assert-equal(false ^ false, false)
@@ -0,0 +1,16 @@
1
+ require("spec/assertions")
2
+
3
+ describe(descriptor, descriptions):
4
+ puts(descriptor)
5
+ descriptions.call()
6
+ puts("")
7
+
8
+ it(description, block):
9
+ success: block.call()
10
+ if success
11
+ print("\e[32m")
12
+ else
13
+ print("\e[31m")
14
+ print("- ")
15
+ print(description)
16
+ puts("\e[0m")
@@ -0,0 +1,15 @@
1
+ require("assertions")
2
+ require("dspec")
3
+
4
+ describe("Float") ->
5
+ it("is equal to an identical float") ->
6
+ assert-equal(1.2, 1.2)
7
+
8
+ it("addable") ->
9
+ assert-equal(1.2 + 0.8, 2.0)
10
+
11
+ it("subtractable") ->
12
+ assert-equal(1.2 - 0.2, 1.0)
13
+
14
+ it("can compare to integers") ->
15
+ assert-equal(2.0, 2)
@@ -0,0 +1,6 @@
1
+ describe("Hash") ->
2
+ it("can be empty") ->
3
+ assert-equal({}, {})
4
+ it("can have keys with values") ->
5
+ assert-not-equal({ foo: "bar" }, {})
6
+ puts { foo: "bar" }
@@ -0,0 +1,18 @@
1
+ describe("Numbers") ->
2
+ it("can be multiplied") ->
3
+ assert-equal(-1 * -1, 1)
4
+
5
+ it("can be added") ->
6
+ assert-equal(1 + 5, 6)
7
+
8
+ it("can be subtracted") ->
9
+ assert-equal(1 - 5, -4)
10
+
11
+ it("can be divided") ->
12
+ assert-equal(6 / 3, 2)
13
+
14
+ it("can do interger division") ->
15
+ assert-equal(3 / 2, 1)
16
+
17
+ it("can be taken to a power") ->
18
+ assert-equal(2 ** 3, 8)
@@ -0,0 +1,12 @@
1
+ test-method:
2
+ "wombat"
3
+
4
+ test-conditional-method:
5
+ if true
6
+ "wombat"
7
+
8
+ describe("Return values") ->
9
+ it("returns the result of a one-line method") ->
10
+ assert-equal("wombat", test-method)
11
+ it("returns the result of a method with a conditional") ->
12
+ assert-equal("wombat", test-conditional-method)
@@ -0,0 +1,18 @@
1
+ describe("String") ->
2
+ it("is equal to an identical string") ->
3
+ assert-equal("foo", "foo")
4
+
5
+ it("is not equal to a different string") ->
6
+ assert-not-equal("foo", "bar")
7
+
8
+ it("can be added to another string") ->
9
+ assert-equal("foo" + "bar", "foobar")
10
+
11
+ it("knows it's length") ->
12
+ assert-equal("foo".length, 3)
13
+
14
+ it("can convert to an Integer") ->
15
+ assert-equal("12".to-i, 12)
16
+
17
+ it("can convert to a Float") ->
18
+ assert-equal("12.5".to-f, 12.5)