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,64 @@
1
+ module Dagon
2
+ module Core
3
+ class DG_Array < DG_Object
4
+ attr_reader :list
5
+ def initialize list, klass
6
+ @list = list
7
+ @klass = klass
8
+ end
9
+
10
+ def to_s
11
+ "["+@list.map(&:to_s).join(", ")+"]"
12
+ end
13
+ end
14
+
15
+ class DG_ArrayClass < DG_Class
16
+ def initialize
17
+ super("Array", Dagon::Core::DG_Class.new)
18
+ end
19
+
20
+ def boot
21
+ add_method "init", ->(vm, ref, value) {
22
+ ref.instance_variable_set("@value", value)
23
+ }
24
+ add_method "[]", ->(vm, ref, index) {
25
+ ref.list[index.value]
26
+ }
27
+ add_method "+", ->(vm, ref, other) {
28
+ DG_Array.new(ref.list + other.list, self)
29
+ }
30
+ add_method "-", ->(vm, ref, other) {
31
+ result = ref.list.reject { |item| other.list.include?(item) }
32
+ DG_Array.new(result, self)
33
+ }
34
+ add_method "=", ->(vm, ref, other) {
35
+ ref.list == other.list ? Dtrue : Dfalse
36
+ }
37
+ add_method "compact", ->(vm, ref) {
38
+ result = ref.list.reject{ |item| item == Dvoid }
39
+ DG_Array.new(result, self)
40
+ }
41
+ add_method "length", ->(vm, ref) {
42
+ vm.get_class("Integer").instance(ref.list.length)
43
+ }
44
+ add_method "each", ->(vm, ref, block) {
45
+ ref.list.each do |item|
46
+ if block.arity == 1
47
+ block.dagon_send(vm, "call", item)
48
+ else
49
+ block.dagon_send(vm, "call")
50
+ end
51
+ end
52
+ }
53
+ end
54
+
55
+ def dagon_new interpreter, value = []
56
+ if value.is_a? DG_Array
57
+ DG_Array.new(value.list, self)
58
+ else
59
+ DG_Array.new(value, self)
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,38 @@
1
+ module Dagon
2
+ module Core
3
+ class DG_Block < DG_Object
4
+ attr_accessor :statements, :frame, :arguments
5
+ def initialize(statements, frame, arguments, klass)
6
+ @statements = statements
7
+ @frame = frame
8
+ @klass = klass
9
+ @arguments = arguments
10
+ end
11
+
12
+ def arity
13
+ @arguments.length
14
+ end
15
+ end
16
+
17
+ class DG_BlockClass < DG_Class
18
+ def initialize
19
+ super("Block", Dagon::Core::DG_Class.new)
20
+ end
21
+
22
+ def boot
23
+ add_method "call", ->(vm, instance, *args) do
24
+ frame = instance.frame.dup
25
+ instance.arguments.each_with_index { |variable_name, index| frame[variable_name] = args[index] }
26
+ vm.push_frame(instance.frame)
27
+ result = instance.statements.map { |statement| statement.evaluate(vm) }.last
28
+ vm.pop_frame
29
+ result
30
+ end
31
+ end
32
+
33
+ def dagon_new interpreter, statements, frame, arguments
34
+ DG_Block.new(statements, frame, arguments, self)
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,91 @@
1
+ module Dagon
2
+ module Core
3
+ class DG_Class
4
+ attr_reader :name, :class_methods
5
+ def initialize name = nil, parent = nil
6
+ @constants = {}
7
+ @methods = {
8
+ methods: ->(vm, ref, *args) { vm.get_class("Array").dagon_new(vm, @methods.keys) },
9
+ init: ->(vm, ref, *args) { },
10
+ exit: ->(vm, ref, *args) { exit(0) },
11
+ puts: ->(vm, ref, *args) { puts *args.map(&:to_s) },
12
+ print: ->(vm, ref, *args) { print *args.map(&:to_s) },
13
+ gets: ->(vm, ref, *args) { vm.get_class("String").dagon_new(vm, $stdin.gets) },
14
+ eval: ->(vm, ref, *args) {
15
+ tokens = Dagon::Scanner.tokenize(args[0].value, '(eval)')
16
+ tree = Dagon::Parser.parse(tokens, '(eval)', false)
17
+ tree.evaluate(vm)
18
+ },
19
+ require: ->(vm, ref, *args) {
20
+ filename = args[0]
21
+ if vm.loaded? filename
22
+ Dfalse
23
+ else
24
+ vm.load_file filename
25
+ Dtrue
26
+ end
27
+ }
28
+ }
29
+ @class_ivars = {}
30
+ @class_methods = {
31
+ methods: ->(vm, ref) {
32
+ vm.get_class("Array").dagon_new(vm, ref.class_methods.keys)
33
+ },
34
+ }
35
+ @name = name || "Class"
36
+ @parent = parent
37
+ boot
38
+ end
39
+
40
+ def dagon_new
41
+ obj = ref.dagon_allocate
42
+ obj.dagon_send(vm, "init", *args)
43
+ obj
44
+ end
45
+
46
+ def boot
47
+ # noop
48
+ end
49
+
50
+ def dagon_const_get constant
51
+ @constants[constant.to_sym]
52
+ end
53
+
54
+ def dagon_const_set constant, value
55
+ @constants[constant.to_sym] = value
56
+ end
57
+
58
+ def add_class_method name, block
59
+ @class_methods[name.to_sym] = block
60
+ end
61
+
62
+ def add_method name, block
63
+ @methods[name.to_sym] = block
64
+ end
65
+
66
+ def get_method name
67
+ @methods[name.to_sym]
68
+ end
69
+
70
+ def dagon_allocate
71
+ DG_Object.new(self)
72
+ end
73
+
74
+ def dagon_send interpreter, name, *args
75
+ method = @class_methods[name.to_sym]
76
+ if method
77
+ method.call(interpreter, self, *args) || Dvoid
78
+ elsif @parent
79
+ @parent.dagon_send(interpreter, name, *args)
80
+ else
81
+ $stderr.puts "undefined method #{name} for #{to_s}"
82
+ exit(1)
83
+ end
84
+ end
85
+
86
+ def to_s
87
+ @name
88
+ end
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,38 @@
1
+ require 'singleton'
2
+
3
+ module Dagon
4
+ module Core
5
+ class False < DG_Object
6
+ include Singleton
7
+
8
+ def initialize
9
+ @value = false
10
+ @klass = DG_FalseClass.new
11
+ end
12
+
13
+ def inspect
14
+ "false"
15
+ end
16
+ end
17
+
18
+ class DG_FalseClass < DG_Class
19
+ undef :dagon_new
20
+ def initialize
21
+ super("False", Dagon::Core::DG_Class.new)
22
+ end
23
+
24
+ def boot
25
+ add_method '!@', ->(vm, ref) {
26
+ Dtrue
27
+ }
28
+ add_method '=', ->(vm, ref, other) {
29
+ ref == other ? Dtrue : Dfalse
30
+ }
31
+ add_method '&&', ->(vm, ref, other) { Dfalse }
32
+ add_method '||', ->(vm, ref, other) { other }
33
+ add_method '^', ->(vm, ref, other) { other }
34
+ add_method 'to-s', ->(vm, ref) { vm.get_class("String").dagon_new(vm, "false") }
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,93 @@
1
+ module Dagon
2
+ module Core
3
+ class DG_Float < DG_Object
4
+ attr_reader :value
5
+ def initialize value, klass
6
+ @value = value
7
+ @klass = klass
8
+ end
9
+
10
+ def == other
11
+ value == other.value
12
+ end
13
+
14
+ def to_s
15
+ @value
16
+ end
17
+
18
+ def inspect
19
+ @value
20
+ end
21
+ end
22
+
23
+ class DG_FloatClass < DG_Class
24
+ undef :dagon_new
25
+
26
+ def initialize value = ""
27
+ super("Float", Dagon::Core::DG_Class.new)
28
+ end
29
+
30
+ def instance value
31
+ DG_Float.new(value, self)
32
+ end
33
+
34
+ def boot
35
+ add_method "+", ->(vm, ref, other) {
36
+ left = ref.value
37
+ right = other.value
38
+ ref.klass.instance(left + right)
39
+ }
40
+ add_method "-", ->(vm, ref, other) {
41
+ left = ref.value
42
+ right = other.value
43
+ ref.klass.instance(left - right)
44
+ }
45
+ add_method "*", ->(vm, ref, other) {
46
+ left = ref.value
47
+ right = other.value
48
+ ref.klass.instance(left * right)
49
+ }
50
+ add_method "/", ->(vm, ref, other) {
51
+ left = ref.value
52
+ right = other.value
53
+ ref.klass.instance(left / right)
54
+ }
55
+ add_method "**", ->(vm, ref, other) {
56
+ left = ref.value
57
+ right = other.value
58
+ ref.klass.instance(left ** right)
59
+ }
60
+ add_method "=", ->(vm, ref, other) {
61
+ left = ref.value
62
+ right = other.value
63
+ left == right ? Dtrue : Dfalse
64
+ }
65
+ add_method "!=", ->(vm, ref, other) {
66
+ left = ref.value
67
+ right = other.value
68
+ left != right ? Dtrue : Dfalse
69
+ }
70
+ add_method ">", ->(vm, ref, other) {
71
+ left = ref.value
72
+ right = other.value
73
+ left > right ? Dtrue : Dfalse
74
+ }
75
+ add_method ">=", ->(vm, ref, other) {
76
+ left = ref.value
77
+ right = other.value
78
+ left >= right ? Dtrue : Dfalse
79
+ }
80
+ add_method "<", ->(vm, ref, other) {
81
+ left = ref.value
82
+ right = other.value
83
+ left < right ? Dtrue : Dfalse
84
+ }
85
+ add_method "<=", ->(vm, ref, other) {
86
+ left = ref.value
87
+ right = other.value
88
+ left <= right ? Dtrue : Dfalse
89
+ }
90
+ end
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,24 @@
1
+ module Dagon
2
+ module Core
3
+ class Frame
4
+ attr_reader :object, :frame_name, :local_variables
5
+ def initialize object, frame_name, local_variables = {}
6
+ @object = object
7
+ @frame_name = frame_name
8
+ @local_variables = local_variables
9
+ end
10
+
11
+ def local_variable? name
12
+ @local_variables.key? name
13
+ end
14
+
15
+ def [](key)
16
+ @local_variables[key]
17
+ end
18
+
19
+ def []=(key, value)
20
+ @local_variables[key] = value
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,51 @@
1
+ module Dagon
2
+ module Core
3
+ class DG_Hash < DG_Object
4
+ attr_reader :hash
5
+ def initialize(assignments, klass)
6
+ @hash = convert_assignments_to_hash_values(assignments)
7
+ @klass = klass
8
+ end
9
+
10
+ def to_s
11
+ hash
12
+ end
13
+
14
+ def inspect
15
+ hash.inspect
16
+ end
17
+
18
+ private
19
+
20
+ def convert_assignments_to_hash_values(assignments)
21
+ hash = {}
22
+ assignments.each do |assignment|
23
+ hash[assignment.variable_name] = assignment.variable_value
24
+ end
25
+ hash
26
+ end
27
+ end
28
+
29
+ class DG_HashClass < DG_Class
30
+ def initialize
31
+ super("Hash", DG_Class.new)
32
+ boot
33
+ end
34
+
35
+ def boot
36
+
37
+ add_method "=", ->(vm, ref, other) do
38
+ ref.hash == other.hash ? Dtrue : Dfalse
39
+ end
40
+
41
+ add_method "!=", ->(vm, ref, other) do
42
+ ref.hash != other.hash ? Dtrue : Dfalse
43
+ end
44
+ end
45
+
46
+ def dagon_new interpreter, assignments
47
+ DG_Hash.new(assignments, self)
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,98 @@
1
+ module Dagon
2
+ module Core
3
+ class DG_Integer < DG_Object
4
+ attr_reader :value
5
+ def initialize value, klass
6
+ @value = value
7
+ @klass = klass
8
+ end
9
+
10
+ def == other
11
+ value == other.value
12
+ end
13
+
14
+ def to_s
15
+ @value
16
+ end
17
+
18
+ def inspect
19
+ @value
20
+ end
21
+ end
22
+
23
+ class DG_IntegerClass < DG_Class
24
+ undef :dagon_new
25
+
26
+ def initialize value = ""
27
+ super("Integer", Dagon::Core::DG_Class.new)
28
+ end
29
+
30
+ def instance value
31
+ DG_Integer.new(value, self)
32
+ end
33
+
34
+ def boot
35
+ add_method "+", ->(vm, ref, other) {
36
+ left = ref.value
37
+ right = other.value
38
+ ref.klass.instance(left + right)
39
+ }
40
+ add_method "-", ->(vm, ref, other) {
41
+ left = ref.value
42
+ right = other.value
43
+ ref.klass.instance(left - right)
44
+ }
45
+ add_method "*", ->(vm, ref, other) {
46
+ left = ref.value
47
+ right = other.value
48
+ ref.klass.instance(left * right)
49
+ }
50
+ add_method "/", ->(vm, ref, other) {
51
+ left = ref.value
52
+ right = other.value
53
+ ref.klass.instance(left / right)
54
+ }
55
+ add_method "**", ->(vm, ref, other) {
56
+ left = ref.value
57
+ right = other.value
58
+ ref.klass.instance(left ** right)
59
+ }
60
+ add_method "=", ->(vm, ref, other) {
61
+ left = ref.value
62
+ right = other.value
63
+ left == right ? Dtrue : Dfalse
64
+ }
65
+ add_method "!=", ->(vm, ref, other) {
66
+ left = ref.value
67
+ right = other.value
68
+ left != right ? Dtrue : Dfalse
69
+ }
70
+ add_method ">", ->(vm, ref, other) {
71
+ left = ref.value
72
+ right = other.value
73
+ left > right ? Dtrue : Dfalse
74
+ }
75
+ add_method ">=", ->(vm, ref, other) {
76
+ left = ref.value
77
+ right = other.value
78
+ left >= right ? Dtrue : Dfalse
79
+ }
80
+ add_method "<", ->(vm, ref, other) {
81
+ left = ref.value
82
+ right = other.value
83
+ left < right ? Dtrue : Dfalse
84
+ }
85
+ add_method "<=", ->(vm, ref, other) {
86
+ left = ref.value
87
+ right = other.value
88
+ left <= right ? Dtrue : Dfalse
89
+ }
90
+ add_method "times", ->(vm, ref, block) {
91
+ ref.value.times do
92
+ block.evaluate vm
93
+ end
94
+ }
95
+ end
96
+ end
97
+ end
98
+ end