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,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