dagon 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +2 -0
- data/.rspec +1 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.md +86 -0
- data/Rakefile +40 -0
- data/bin/dagon +44 -0
- data/bin/dspec +35 -0
- data/bin/idg +15 -0
- data/bin/idgr +16 -0
- data/build/parser.rb +1015 -0
- data/build/scanner.rb +686 -0
- data/core/array.rb +64 -0
- data/core/block.rb +38 -0
- data/core/class.rb +91 -0
- data/core/false.rb +38 -0
- data/core/float.rb +93 -0
- data/core/frame.rb +24 -0
- data/core/hash.rb +51 -0
- data/core/integer.rb +98 -0
- data/core/object.rb +50 -0
- data/core/string.rb +57 -0
- data/core/true.rb +37 -0
- data/core/vm.rb +125 -0
- data/core/void.rb +37 -0
- data/dagon.gemspec +19 -0
- data/dagon.vim +45 -0
- data/dagon/ast/array_node.rb +17 -0
- data/dagon/ast/assignment_node.rb +21 -0
- data/dagon/ast/block_node.rb +19 -0
- data/dagon/ast/class_definition_node.rb +24 -0
- data/dagon/ast/constant_ref_node.rb +15 -0
- data/dagon/ast/frame.rb +23 -0
- data/dagon/ast/function_call_node.rb +33 -0
- data/dagon/ast/function_definition_node.rb +15 -0
- data/dagon/ast/function_node.rb +23 -0
- data/dagon/ast/hash_node.rb +16 -0
- data/dagon/ast/if_node.rb +20 -0
- data/dagon/ast/instance_init_node.rb +28 -0
- data/dagon/ast/instance_var_ref_node.rb +21 -0
- data/dagon/ast/literal_node.rb +23 -0
- data/dagon/ast/node.rb +22 -0
- data/dagon/ast/root_node.rb +19 -0
- data/dagon/ast/string_node.rb +16 -0
- data/dagon/ast/unary_function_call_node.rb +17 -0
- data/dagon/ast/var_ref_node.rb +19 -0
- data/dagon/ast/while_node.rb +17 -0
- data/dagon/parser.y +151 -0
- data/dagon/scanner.rl +143 -0
- data/examples/assert.dg +8 -0
- data/examples/assignment.dg +2 -0
- data/examples/block.dg +8 -0
- data/examples/class.dg +6 -0
- data/examples/conditional.dg +3 -0
- data/examples/conditions.dg +6 -0
- data/examples/equality.dg +6 -0
- data/examples/error.dg +1 -0
- data/examples/eval.dg +1 -0
- data/examples/fibonacci.dg +15 -0
- data/examples/greeter.dg +6 -0
- data/examples/input.dg +3 -0
- data/examples/instance_variables.dg +11 -0
- data/examples/iterate.dg +2 -0
- data/examples/method_call.dg +9 -0
- data/examples/method_definition.dg +4 -0
- data/examples/operators.dg +6 -0
- data/examples/output.dg +1 -0
- data/examples/require.dg +1 -0
- data/spec/array_spec.dg +26 -0
- data/spec/assertions.dg +11 -0
- data/spec/boolean_spec.dg +48 -0
- data/spec/dspec.dg +16 -0
- data/spec/float_spec.dg +15 -0
- data/spec/hash_spec.dg +6 -0
- data/spec/number_spec.dg +18 -0
- data/spec/return_spec.dg +12 -0
- data/spec/string_spec.dg +18 -0
- data/spec/void_spec.dg +9 -0
- data/spec/while_spec.dg +7 -0
- metadata +180 -0
data/dagon/scanner.rl
ADDED
@@ -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
|
data/examples/assert.dg
ADDED
data/examples/block.dg
ADDED
data/examples/class.dg
ADDED
data/examples/error.dg
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
1 + 2()
|
data/examples/eval.dg
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
eval("puts(\"Hello wombat\")")
|
data/examples/greeter.dg
ADDED
data/examples/input.dg
ADDED
data/examples/iterate.dg
ADDED
data/examples/output.dg
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
puts("Hello world")
|
data/examples/require.dg
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require("greeter")
|
data/spec/array_spec.dg
ADDED
@@ -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)
|
data/spec/assertions.dg
ADDED
@@ -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)
|
data/spec/dspec.dg
ADDED
@@ -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")
|
data/spec/float_spec.dg
ADDED
@@ -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)
|
data/spec/hash_spec.dg
ADDED
data/spec/number_spec.dg
ADDED
@@ -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)
|
data/spec/return_spec.dg
ADDED
@@ -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)
|
data/spec/string_spec.dg
ADDED
@@ -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)
|