dagon 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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)